在实体框架中 EntityState.Detached 使操作变慢

Posted

技术标签:

【中文标题】在实体框架中 EntityState.Detached 使操作变慢【英文标题】:In Entity Framework EntityState.Detached makes operation slow 【发布时间】:2020-05-25 20:00:57 【问题描述】:

在调试以下代码时,我发现 forEach 需要花费大量时间,将 6000 条记录的状态从 EntityState.Unchanged 更改为 EntityState.Detached 在我的本地开发环境中大约需要 16 分钟。

'where' 表达式正在过滤记录,而 'update' 表达式仅更新单个列。

我尝试将 ProxyCreationEnabled 和 LazyLoadingEnabled 设置为 false,但仍然需要相同的时间。这段代码有什么问题?

DbSet = Context.Set<T>();
...
...
public virtual int UpdateDB(Expression<Func<T, T>> update, Expression<Func<T, bool>> where)
        
                    var recordsUpdated = DbSet.Where(where).Update(update);
                    foreach (var e in DbSet.Where(where))
                    
                        var state = Context.Entry(e).State;
                        Context.Entry(e).State = EntityState.Detached;
                        state = Context.Entry(e).State;
                    
                    return recordsUpdated;                
            

        

【问题讨论】:

这个 Update 方法到底发生了什么?我怀疑你在那里打电话给SaveChanges 并且有一些你试图“重置”的静态上下文。这是几种不良做法的结合。 @GertArnold 在这段代码中,我们尝试使用 where 和 update 表达式直接更新 DbSet。我发现var recordsUpdated = DbSet.Where(where).Update(update); 行执行得非常快,但是Context.Entry(e).State = EntityState.Detached; 行似乎需要更多时间循环每条记录,这里我们试图将状态从未更改更改为已分离。 这并不能真正回答我的问题。我试图找出你为什么要做你正在做的事情。您不需要将状态设置为分离。它可能使更改跟踪器非常忙碌(在臃肿的上下文中一直调用 DetectChanges)。您应该简单地处理上下文。这种更新,如果使用 EF 完成,应该通过创建存根实体来完成。 @GertArnold 很抱歉我对 EF 世界很陌生。我正在尝试分离实体,以便 EF 不跟踪它,但这看起来是个非常糟糕的主意,因为它使更改跟踪器保持忙碌。我将阅读更多关于处理上下文的内容。谢谢。 【参考方案1】:

这段代码有什么问题?

那个代码很昂贵而且没有意义。

这个

var recordsUpdated = DbSet.Where(where).Update(update);

似乎正在从数据库中获取每一行并通过Update 函数运行。那么这个

foreach (var e in DbSet.Where(where))

正在从数据库中获取每一行再次,但是将它们全部与跟踪的实体进行匹配,并返回跟踪的实体,而不是它刚刚从数据库中获取的实体。实体条目的状态被翻转为分离并返回到之前的状态。

你想完成什么?

如果要更新表中的每一行,请直接使用 SQL。不要将它们全部获取给客户端,更改它们并保存回来。

【讨论】:

以上是关于在实体框架中 EntityState.Detached 使操作变慢的主要内容,如果未能解决你的问题,请参考以下文章

撤消实体框架实体中的更改

实体框架分离实体和相关实体消失

在实体框架中更新具有所需属性的实体

Expression.Invoke 在实体框架中?

防止在实体框架中的相关表实体上添加新记录

无法在实体框架中更新具有唯一约束索引的实体