问题描述
||
我使用LinqToEntitiesDomainService类通过Silverlight 4客户端更新数据库。
实体框架ObjectContext的AttachAsModified扩展方法可让您提供原始的实体属性值:
Order original = this.ChangeSet.Getoriginal(currentOrder);
this.ObjectContext.Orders.AttachAsModified(currentOrder,original);
默认情况下,WCF RIA Services不会将原始值发送到服务器,因此需要
将[roundtripOriginal()]属性应用于他/她的实体。
但是,即使我提供原始值,由Entity Framework生成的sql也会更新所有列,而不仅是更改的列。由于AttachAsModified()方法不是本机ObjectContext类方法(它是ObjectContextExtensions类中定义的扩展方法),因此我尝试使用
在ObjectSet类中定义的ApplyOriginalValues方法。不用找了。
看来最近发布的实体框架4.1可能有解决方案(不确定)。实体框架4呢? EF是否可以生成sql以仅更新更改的列?
解决方法
我确实在MSDN论坛上提出了类似的问题,并且可以肯定WCF RIA Services将更改所有列。替代方法是
您可以从数据库中获取副本,使用反射手动比较和标记SetModifiedProperty。
// change state of entity as Unmodified/Unchanged...
original.EntityState = Unchanged;
// this is copy form database...
// Use different context
MyOrderContext context = new MyOrderContext();
Order dbOriginal = context.Orders.First( x=>x.OrderID == original.OrderID);
foreach(PropertyInfo p in copy.GetTypes().GetProperties()){
Object originalValue = p.GetValue(dbOriginal);
Object newValue = p.GetValue(original);
if(originalValue!=null && newValue!=null
&& originalValue.Equals(newValue)){
continue;
}
// resetting this will
// make entity\'s only current
// property as changed
p.SetValue(original,originalValue);
p.SetValue(original,newValue);
}
您可能需要根据情况更改代码,检查属性是否为只读,这只是一个示例,但是它将帮助您在此基础上进行构建。
, AttachAsModified会将实体标记为已修改。随后(引自MSDN):
当您更改
实体对象条目全部为“已修改”
该对象的属性是
标记为已修改,无论
当前或原始值。
警告;我还没有做到这一点,但是应该可以。
不要使用AttachAsModified,而是使用ChangeState方法将实体标记为UnChanged。
然后,对已更改的属性使用SetModifiedProperty方法,以使其包含在更新中。
编辑:如果您想要一种方法来查找已更改的属性,有几篇文章在那里解释了如何使用ObjectStateManager这样的对象
, 通过首先附加对象,然后在EntitySet上调用ApplyOriginalValues,我设法做到了这一点。您将需要一个具有原始值的对象来执行此操作。此方法还可以用于防止列被更新,例如用于行级安全性。
注意:不幸的是,如果不先从数据库中检索原始实体,此方法将无法工作。否则,只会将设置为默认值的属性排除在更新之外...