我试图在Web API上为将存储在DB中的对象实现PATCH。来自控制器的输入对象具有可以修改的所有属性,但我们允许客户端选择要发回的字段。如果某些字段已更改或已设置,我们只想更新MongoDB表示。我们开始使用Dirty对象模式(不确定这是一个模式),当你设置一个属性时,你也会记录它是脏的。例如
public class Example
{
private string _title;
public string Title
{
get { return _title; }
set
{
_title = value;
TitleWasSet = true;
}
}
public bool TitleWasSet {get;set;}
}
这可行,但有点乏味,我觉得它暴露了许多可以包含的逻辑。
因此,我提出的解决方案是将更新操作存储在入站对象中,然后以Try Update方式将它们重新应用于Mongo对象。
像这样:public class Data
{
public string Header { get; set; }
public int Rating { get; set; }
}
public class EditDataRequest
{
private readonly List<Action<Data>> _updates;
public EditDataRequest()
{
_updates = new List<Action<Data>>();
}
public string Header
{
set
{
_updates.Add(data => {data.Header = value;});
}
}
public int Rating
{
set
{
_updates.Add(data => {data.Rating = value;});
}
}
public bool TryUpdateFromMe(Data original)
{
if (_updates.Count == 0)
return false;
foreach (var update in _updates)
{
update.Invoke(original);
}
return true;
}
}
现在这会很好用,但它没有考虑到相同的值。所以我然后考虑将操作列表更改为一个函数列表,如果值存在差异则返回bool。
private readonly List<Func<Data, bool>> _updates;
然后属性看起来像这样:
public int Rating
{
set
{
_updates.Add(data => {
if (data.Rating != value)
{
data.Rating = value;
return true;
}
return false;
});
}
}
尝试更新方法......
public bool TryUpdateFromMe(Data original)
{
if (_updates.Count == 0)
return false;
bool changesRequired = false;
foreach (var update in _updates)
{
changesRequired |= update.Invoke(original);
}
return changesRequired;
}
正如您所看到的,属性集实现相当笨重,并且会使代码难以阅读。
我想要一种提取检查此属性值的方法,然后将其更新为另一种我可以在每个属性中重用的方法 - 我认为这可能是某种方式,但可能不是。
当然,如果您对如何处理PATCH情况有更好的建议,那么我也很乐意听到它们。
感谢您阅读此内容。