2010-03-17 75 views
42

我将几个实体添加到对象上下文中。如何清理实体框架对象上下文?

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) 

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

+7

我建议不重用ObjectContext的。有些情况下,它是有道理的,但它们非常罕见。请记住,使用ObjectContext的时间越长,它就越容易获得,如果它进入不一致的状态(即部分完成),则可能会产生一些不一致的副作用。 – 2010-03-18 05:56:56

回答

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

,无法看到它。

+7

顺便有可能使用位标志做VAR objectStateEntries = this._context.ObjectStateManager .GetObjectStateEntries(EntityState.Added | EntityState.Deleted | EntityState.Modified | EntityState.Unchanged);分离所有附加的物体 – 2011-11-18 13:11:17

+0

将其标记为答案。 – 2012-05-07 23:58:41

+0

请注意,在某些情况下,'objectStateEntry.Entity'将为null('objectStateEntity'描述一个没有实体的关系),所以你应该在那里放一个空检查。 – 2014-02-18 19:41:26

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的 - 我们正在使用的统一,使一个新创建生成这些,如果旧的已处置

+2

使用工作单元仍然不会从上下文中分离对象。它也不回答这个问题。 – 2015-07-15 11:24:01

+0

@AgentShark完全取决于如何实现'Rollback'方法。此外,还有没有点复制正确的代码在接受的答案,显示明确如何分离对象 – Basic 2015-07-15 14:29:52

+0

我重读的问题。是通过一个工作单元强制更新会很有用。但是在EF中,添加对象与相关实体时必须小心。不同的行为存在不同的方式来添加/保存对象到上下文。 – 2015-07-22 15:04:56

36

丹尼尔的答案为我工作,但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; 
      } 
     } 
    } 
+0

这个方法对我的作品:-D感谢! – duardbr 2016-02-07 20:22:35

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

对于使用实体框架的核心1.0 RC2 +的,我更新Garrys的回答。

参考

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