如何通过覆盖 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() 调用?的主要内容,如果未能解决你的问题,请参考以下文章

使用关联覆盖实体删除

launch4j:通过命令行覆盖默认 JVM 堆大小

通过实体框架更新时如何绕过唯一键约束(使用 dbcontext.SaveChanges())

如何更改 DbContext.SaveChanges() 的条目值

CMAKE_INSTALL_PREFIX如何设置默认值,并且保留从命令行覆盖的能力?

如果在 Db 上修改了先前加载的实体,如何将 EF 设置为不让 saveChanges?