代码之家  ›  专栏  ›  技术社区  ›  Daniel Brückner Pradip

如何清理实体框架对象上下文?

  •  44
  • Daniel Brückner Pradip  · 技术社区  · 14 年前

    我正在向对象上下文添加多个实体。

    try
    {
        forach (var document in documents)
        {
            this.Validate(document); // May throw a ValidationException.
    
            this.objectContext.AddToDocuments(document);
        }
    
        this.objectContext.SaveChanges();
    }
    catch
    {
        // How to clean-up the object context here?
    
        throw;
    }
    

    如果某些文档通过了验证,而其中一个文档失败,则所有通过验证的文档都会添加到对象上下文中。我必须清理对象上下文,因为它可能被重用,并且可能发生以下情况。

    var documentA = new Document { Id = 1, Data = "ValidData" };
    var documentB = new Document { Id = 2, Data = "InvalidData" };
    var documentC = new Document { Id = 3, Data = "ValidData" };
    
    try
    {
        // Adding document B will cause a ValidationException but only
        // after document A is added to the object context.
        this.DocumentStore.AddDocuments(new[] { documentA, documentB, documentC });
    }
    catch (ValidationException)
    {
    }
    
    // Try again without the invalid document B. This causes an exception because
    // of a duplicate primary key - document A with id 1 is added a second time.
    this.DocumentStore.AddDocuments(new[] { documentA, documentC });
    

    这将再次将文档A添加到对象上下文中,从而 SaveChanges() 由于主键重复,将引发异常。

    因此,如果出现验证错误,我必须删除所有已添加的文档。当然,我可以先执行验证,并且只在成功验证之后添加所有文档,但遗憾的是,这并不能解决整个问题-如果 保存更改() 失败,所有文档仍保持添加状态,但未保存。

    我试图分离所有返回的对象

     this.objectContext.ObjectStateManager.GetObjectStateEntries(EntityState.Added)
    

    但我得到一个例外,说明这个物体没有附着。那么,如何除去所有已添加但未保存的对象呢?

    5 回复  |  直到 8 年前
        1
  •  41
  •   Garry English    10 年前

    Daniel的答案对我很有用,但是EntityFramework API在版本6+中是不同的。下面是我添加到自定义存储库容器中的一个方法,它将从dbContext的changeTracker中分离所有实体:

        /// <summary>
        /// Detaches all of the DbEntityEntry objects that have been added to the ChangeTracker.
        /// </summary>
        public void DetachAll() {
    
            foreach (DbEntityEntry dbEntityEntry in this.Context.ChangeTracker.Entries()) {
    
                if (dbEntityEntry.Entity != null) {
                    dbEntityEntry.State = EntityState.Detached;
                }
            }
        }
    
        2
  •  38
  •   Daniel Brückner Pradip    14 年前

    这只是一个微不足道的错误,但我将把这个问题留在这里-也许它可以帮助其他人。

    我有以下几点

    var objectStateEntries = this.objectContext
                                 .ObjectStateManager
                                 .GetObjectStateEntries(EntityState.Added);
    
    foreach (var objectStateEntry in objectStateEntries)
    {
        this.objectContext.Detach(objectStateEntry);
    }
    

    当我想要以下

    foreach (var objectStateEntry in objectStateEntries)
    {
        this.objectContext.Detach(objectStateEntry.Entity);
    }
    

    却看不见。

        3
  •  1
  •   Basic    14 年前

    参加聚会有点晚了,但你考虑过单位工作模式吗?

    简而言之,它允许您拥有一个事务,然后您可以回滚(释放)或提交(保存更改)。

    注意:这是事务,就像将更改分组为一个操作一样,而不是像在SQL BEGIN事务中那样。这一切仍然由savechanges()方法为您处理。

    比如:

    Public Class UnitOfWork
        Implements IUnitOfWork
        Implements IDisposable
        Private ReadOnly Property ObjectContext As Interfaces.IObjectContext
    
        Public Sub New(ByVal objectContext As Interfaces.IObjectContext)
            _objectContext = objectContext
        End Sub
    
        Public Sub Dispose() Implements IDisposable.Dispose
            If _objectContext IsNot Nothing Then
                _objectContext.Dispose()
            End If
            GC.SuppressFinalize(Me)
        End Sub
    
        Public Sub Commit() Implements IUnitOfWork.Commit
            _objectContext.SaveChanges()
        End Sub
    End Class
    

    每次创建一个工作单元时,都需要一个对象上下文-我们使用Unity来生成这些单元,这样,如果旧的单元已被释放,就可以创建一个新的单元。

        4
  •  1
  •   oɔɯǝɹ    9 年前
    var entries = ((DbContext)ef).ChangeTracker.Entries();
    foreach (var entry in entries)
    {
        entry.State = System.Data.EntityState.Detached;
    }
    
        5
  •  1
  •   Arthur Silva    8 年前

    对于那些使用 实体框架核心1.0 RC2+ ,我更新了加里斯的答案。

    参考

    using Microsoft.EntityFrameworkCore;
    using Microsoft.EntityFrameworkCore.ChangeTracking;
    

    更新的代码

            /// <summary>
            /// Detaches all of the EntityEntry objects that have been added to the ChangeTracker.
            /// </summary>
            public void DetachAll()
            {
                foreach (EntityEntry entityEntry in this.Context.ChangeTracker.Entries().ToArray())
                {
                    if (entityEntry.Entity != null)
                    {
                        entityEntry.State = EntityState.Detached;
                    }
                }
            }