仅更新未设置为null的EF实体上的某些属性

我有一个浏览器发送JSON但它只包含已更改的给定模型的属性。 因此,一旦WCF DataContractJsonSerializer完成它的工作,我就有一个对象,可能只填充了ID和Description字段。

将其附加到DbContext将导致描述字段被更新,但所有其他字段被设置为其类型在数据库中的默认值。 这是因为如果WCF没有看到JSON中指定的属性,那么它将跳过它,这意味着实例中的属性将根据自动实现的属性使用类型默认值。

所以这意味着我需要决定在没有访问JSON本身的情况下传递了哪些字段。 事实上,它可能是线上的XML,所以我可以使用的是这个部分序列化的对象。

最合乎逻辑的是使用null作为特殊值,这意味着此属性尚未被序列化。 所以在POCO模型的构造函数中,我将所有属性设置为null

在Update方法中,然后使用此序列化对象作为存根。 我必须遍历每个属性,如果值没有设置为null,那么我将其状态设置为modified。 据我所知,这是没有任何副作用的工作,但我只是不确定这是做这样的事情的方式。

它添加的一个限制是客户端不能再故意将属性设置为null,因为该更新将丢失。 解决此问题的一种方法是使用一个特殊的int值,可以设置为在数据库中表示null,也可以是一个空字符串,表示数据库中的null,并在更新中使用代码查找这些特殊值,然后设置实体属性为null。 远非理想,可能容易出错。

这是我目前处理更新的代码。 我真的非常感谢有关更好,也许更明显的做法的建议。

夏季:如何判断模型实例上的哪些属性已由DataContractSerializer / DataContractJsonSerializer设置,哪些属性仅使用其构造函数的默认值。 使用特殊值是有问题的,因为客户端可能希望将某些内容设置为空字符串,或者设置为0或-1或实际上为null。

public T Update(T obj) { var entity = ds.Attach(obj); // For each property in the model foreach (var p in typeof(T).GetProperties()) { // Get the value of the property var v = p.GetValue(obj, null); // Assume null means that the property wasn't passed from the client if (v == null) continue; // Set this property on the entity to modified unless it's ID which won't change if (p.Name != "ID") dc.Entry(entity).Property(p.Name).IsModified = true; } dc.SaveChanges(); return entity; } 

更新:使用Hammerstein的答案来获得自我跟踪的模型,我已经更新了我的更新function,如下所示。 不幸的是,由于我在模型上使用了必需属性以进行预保存validation,因此当使用包含非修改值的空值的存根实例时,EF会引发抖动。 您会认为EF会在其validation中认识到某些字段设置为未修改,但唉不是这样,我不得不进行读取然后更新。 实际上,这可能是一个很好的候选人,可以发布一个单独的问题来试图避免阅读。

 public virtual T Update(T obj) { var entity = ds.Find(obj.ID); ((TrackedModel)obj).Modified.ForEach(p => { var prop = dc.Entry(entity).Property(p.PropertyName); prop.CurrentValue = p.NewValue; prop.IsModified = true; }); dc.SaveChanges(); return entity; } 

我对这个问题的解决方案是跟踪更改模型,我创建了一个包含字符串列表的抽象基类,然后对于模型中的每个属性,我调用了一个方法NotifyChanged(“MyProperty”),它将属性添加到列表中。

由于模型绑定仅设置已回发的字段,因此您应该获得更改的字段的准确列表。

然后我遍历列表,并在我的实体上设置值。

不干净,但它符合我的目的。

更新 :我的解决方案确实要求我远离自动属性并手写它们。 在setter中,设置值后,我调用NotifyChanged。 我正在使用MVC常规模型绑定,我不认为我有一个将对象作为JSON和反序列化传递的工作示例。 您可以查看JSON.NET,控制序列化/反序列化我相信您可以告诉它忽略默认属性值等。