昨天我遇到了一个问题。我被要求编写一个 rest 服务,它公开了一个类的所有属性。消费者都会使用不同的属性,并且在提交时,他们都会发送不同的属性子集。例如,让我们打电话给合同公司。
class Company{
public string Address {get;set;}
public string CompanyNumber {get;set;}
public string Turnover {get;set;}
public string Employees {get;set;}
}
假设我们有两个已知的系统想要同步公司类。系统 1 处理会计,想要读取地址和更新营业额。系统 2 处理人力资源,并希望读取地址并更新员工。现在,通常当遇到这个问题时,人们会编写许多接口,每个接口都有一个量身定制的合约以适应最终系统。然而,我被告知这不是他们想要的。相反,如果属性是在 JSON 中提供的,则必须对其进行设置。
问题是,当从 JSON 反序列化类 Company 时,如果未提供属性,则该属性为 null,这将在映射到数据库类时覆盖数据。
我想出的解决方案是创建一个可选结构,如 Nullable,但其中 null 也可以是有效值。反序列化时,此结构可以跟踪属性是否已设置,因此在 JSON 中提供。然后,我可以在从 DTO 映射到数据库类时检查这一点,并且仅在设置属性时进行映射:)
https://dotnetfiddle.net/QmHtSW
public interface IOptional
{
bool HasBeenSet { get; }
}
public struct Optional<T> : IOptional
{
internal readonly T Val;
public Optional(T value)
{
Val = value;
HasBeenSet = true;
}
public Optional(Optional<T> value)
{
Val = value.Value;
HasBeenSet = value.HasBeenSet;
}
public bool HasBeenSet { get; }
public override bool Equals(object obj)
{
return obj.Equals(Val);
}
public override int GetHashCode()
{
return Val.GetHashCode();
}
public static implicit operator T(Optional<T> optional)
{
return optional.Val;
}
public static implicit operator Optional<T>(T optional)
{
return new Optional<T>(optional);
}
public T Value => Val;
}
和我的自动映射器映射配置文件
CreateMap<TRestObject, TDomainObject>()
.ForAllMembers(mo=>mo.Condition(f =>
{
var opt = f.SourceValue as IOptional;
return opt==null || opt.HasBeenSet;
}));