如何通过覆盖 SaveChanges() 的默认行为来执行多个 SaveChanges() 调用?
Posted
技术标签:
【中文标题】如何通过覆盖 SaveChanges() 的默认行为来执行多个 SaveChanges() 调用?【英文标题】:How can I execute multiple calls of SaveChanges() by overriding default behaviour of SaveChanges()? 【发布时间】:2013-10-19 05:53:03 【问题描述】:我使用 EntityFramework 4.1。
我想要实现的是,每当对 FooEntity 的实体调用 SaveChanges 方法时,我首先要更新这些实体,然后再删除。
我尝试覆盖下面的默认行为,但我无法实现我想要的:它在 Db 上更新。但不能删除。
我怎样才能做到这一点?
public override int SaveChanges()
var entitiesMarkedAsDelete = ChangeTracker.Entries<FooEntity>()
.Where(e => e.State==EntityState.Deleted);
foreach (var e in entitiesMarkedAsDelete)
e.State = EntityState.Modified;
base.SaveChanges(); // To enforce an UPDATE first
// Now, I try to re-mark them to DELETE
foreach (var e in entitiesMarkedAsDelete)
e.State = EntityState.Deleted;
base.SaveChanges(); // And hope that they will be deleted
// RESULT: 1st call of base.Savechanges() updates the entities
// but the 2nd call of base.Savechanges() does not make any changes on the UPDATED
// entities -and they are NOT DELETED.
【问题讨论】:
我认为第一次调用 SaveChanges 会以某种方式刷新 changeTracker,即使我将 EntityState 更改为 Deleted,它也会忽略这一点。但即使我是对的,我也不知道该如何处理。 我相信你有充分的理由这样做......但在我看来删除之前的更新似乎毫无意义? 嗯,这在某种程度上是由于当前审计实体的设计发生了变化。而且如果我不先更新,我将无法获取删除记录的用户名。 【参考方案1】:我认为您在这里被 LINQ 的懒惰性质愚弄了。
您在此处创建的序列:
var entitiesMarkedAsDelete = ChangeTracker.Entries<FooEntity>()
.Where(e => e.State==EntityState.Deleted);
.. 每次迭代时都会对其进行评估,因此第二次 foreach 遍历它时,实际上并没有得到任何结果,因为不再有实体处于已删除状态。
因此,要解决此问题,您只需将序列通过管道传输到 fx。一个列表,通过调用.ToList
就可以了:
var entitiesMarkedAsDelete = ChangeTracker.Entries<FooEntity>()
.Where(e => e.State==EntityState.Deleted).ToList();
这样,两个 foreach 语句都将遍历相同的实体,并且应该正确删除它们。
【讨论】:
彼得这帮助了我想要实现的目标。在第一个 SaveChanges 中,它提交并在第二个中删除。但我认为它们根本没有在事务中完成,因此如果 DELETE 失败,则不会回滚 UPDATE。对吗? 是的,现在这两个调用的工作方式是两个不同的事务,所以它不会回滚更新。但是您应该能够将它们组合在一个事务中。 Here is some info 最后一件事:你认为包含 .Detached 状态是否有意义? 嗯,真的不明白为什么这样做有任何意义 :)以上是关于如何通过覆盖 SaveChanges() 的默认行为来执行多个 SaveChanges() 调用?的主要内容,如果未能解决你的问题,请参考以下文章
通过实体框架更新时如何绕过唯一键约束(使用 dbcontext.SaveChanges())
如何更改 DbContext.SaveChanges() 的条目值