我有一个在API函数中使用的DTO,并使用[FromBody]
进行Map:
public class ExampleDto
{
public int? PropertyA { get; init; }
public string PropertyB { get; init; }
}
public ... Update([FromBody] ExampleDto dto, ...)
{
}
如果JSON
请求体中省略了PropertyA
,它在dto
中仍被视为null
,但我希望允许提供实际的null
值,以便执行一些逻辑。
那么,如何区分显式的null
值和从请求中省略的属性值呢?
为了清楚起见:
{
"propertyB": "Some value"
}
PropertyA
已从请求中省略,因此不使用该属性执行任何逻辑。但是,从请求到DTO的Map导致该属性仍然具有null
值。
{
"propertyA": null,
"propertyB": "Some value"
}
PropertyA
已作为null
提供,表示数据库中的值应设置为null
。
4条答案
按热度按时间zi8p0yeb1#
我能想到的唯一方法是通过继承JsonConverter并实现自己的JsonDeserializer来编写自己的自定义JsonDeserializer。在这种情况下,你可以看到你解析出来的属性名,然后你可以设置存在的属性名,或者作为另一个属性设置器,或者只是作为目标类上的字符串列表或其他东西。那你就能做出区分了
zzwlnbp82#
你可以用JsonConverter属性来修饰你的类,它会处理你特殊的反序列化逻辑:
JsonConverter看起来像这样:
zhte4eai3#
由于OP指出一个公共基类可以用于所有DTO(无论如何,这是一个很好的实践),因此这里有一个解决方案,它不需要自定义反序列化器,并且可以使数据库更新逻辑变得简单。
这利用了这样一个事实:如果属性不在JSON字符串中,JSON反序列化器默认不会调用属性设置器,但如果属性为null或默认值,则会调用属性设置器(除非您通过装饰器或自定义反序列化设置更改此行为-所以不要这样做)。
Update
方法将允许您获取现有的数据库记录,并提供更新/请求对象,仅分配那些通过JSON显式设置的值。因此,使用您的示例,您的DTO将变为:
下面是一些使用JSON.NET或System.Text.JSON测试的代码:
如果进行调试,您将看到后两个对象在其
_values
字典中有两个成员,而前两个对象只有一个成员。在实际的API中,您将-
Update
另外,如果您正在构建自己的
UPDATE
语句,那么您可以扩展DTOBase
来访问_values
字典,从而形成更新的基础。唯一的缺点是需要重构所有的DTO属性getter和setter,但请记住,这种抽象不仅可以获得所需的信息,还可以获得JSON对象与不,但也使得在数据库更新过程中使用这些信息变得非常容易和可扩展。
igetnqfo4#
你可以试试这个:
或
像这样使用属性: