你更新...
var f = db.Foos.First(x => someEqualityTest(foo));
f = foo;
...将无法正常工作,因为你没有改变加载和连接对象f
可言,你只是覆盖变量f
与分离对象foo
。附加的对象仍然在上下文中,但是在加载后它没有被改变,并且你没有指向它的变量。 SaveChanges
在这种情况下不会做任何事情。
“标准选项”你们是:
var f = db.Foos.First(x => someEqualityTest(foo));
db.Entry(f).State = EntityState.Modified;
或只是
db.Entry(foo).State = EntityState.Modified;
// attaches as Modified, no need to load f
这标志着作为修改的所有特性 - 如果他们真的改变与否没有关系 - 并且将发送更新为数据库的每一列。
这只会标志着真正改变属性修改,并只发送了更改的列的UPDATE第二个选项:
var f = db.Foos.First(x => someEqualityTest(foo));
db.Entry(f).CurrentValues.SetValues(foo);
现在,200万点要更新的对象,你没有一个“标准“的情况,并且可能的是,两种选择 - 特别是可能使用内部反射来匹配源和目标对象的属性名称的第二种 - 太慢。
当涉及到更新性能时,最好的选择是更改跟踪代理。这意味着您需要将实体类中的EVERY属性标记为virtual
(不仅是导航属性,还包括标量属性),并且您不禁止创建更改跟踪代理(默认情况下启用)。
当您从数据库加载对象f
时,EF将创建一个动态代理对象(从您的实体派生),类似于延迟加载代理,它将代码注入到每个属性设置器中以维护标志,被改变或没有。
代理提供的更改跟踪比基于快照的更改跟踪(发生在SaveChanges
或DetectChanges
)快得多。
我不确定,如果您使用更改跟踪代理,上述两个选项更快。这可能是你需要手动属性分配,以获得最佳性能:
var f = db.Foos.First(x => someEqualityTest(foo));
f.Property1 = foo.Property1;
f.Property2 = foo.Property2;
// ...
f.PropertyN = foo.PropertyN;
在我类似的更新情况经验对象的几千元也没有改变对性能跟踪代理真正的替代品。
你能摆脱你如何检查多一点光,如果两个实例Foo是平等的吗?这是一个简单的ID比较? – 2012-03-28 17:43:54
可能是,我只是想概括一下具体细节,并将注意力放在解决方案的较大逻辑方面 – Didaxis 2012-03-28 18:33:47