如何清理Entity Framework对象上下文?

时间:2010-03-17 21:09:14

标签: c# entity-framework

我在对象上下文中添加了几个实体。

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()将因重复的主键而引发异常。

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

我试图分离

返回的所有对象
 this.objectContext.ObjectStateManager.GetObjectStateEntries(EntityState.Added)

但我得到一个例外,说明该对象未附加。那么如何摆脱所有已添加但未保存的对象?

6 个答案:

答案 0 :(得分:41)

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;
            }
        }
    }

答案 1 :(得分:38)

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

我有以下

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);
}

并且看不到它。

答案 2 :(得分:1)

派对有点晚,但你考虑过工作单位模式吗?

简而言之,它允许您拥有一个事务,然后您可以回滚(处置)或提交(savechanges)

注意:这是将更改分组到一个操作中的事务,而不是在sql BEGIN TRAN中。这仍然是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

每次创建一个工作单元时,它都会引入一个objectcontext - 我们正在使用Unity来生成这些文件,以便在旧文件处理完毕后创建一个新文件

答案 3 :(得分:1)

var entries = ((DbContext)ef).ChangeTracker.Entries();
foreach (var entry in entries)
{
    entry.State = System.Data.EntityState.Detached;
}

答案 4 :(得分:1)

对于使用 Entity Framework Core 1.0 RC2 + 的用户,我更新了Garrys&#39;答案。

<强>参考

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;
                }
            }
        }

答案 5 :(得分:1)

Since EF Core 5.0使用ChangeTracker.Clear()清除所有跟踪实体的DbContext。