2010-03-17 2 views
42

개체 컨텍스트에 여러 엔터티를 추가하려고합니다. 문서의 일부가 유효성 검사를 통과하고 하나가 실패하면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 }); 

다시 때문에 중복 된 기본 키의 예외가 발생합니다 개체 컨텍스트와 결과 SaveChanges() 문서 A를 추가합니다.

그래서 유효성 검사 오류의 경우 이미 추가 된 모든 문서를 제거해야합니다. 물론 유효성 검사를 먼저 수행하고 성공적으로 검증 된 후에 만 ​​모든 문서를 추가 할 수는 있지만 슬프게도이 문제는 전체 문제를 해결하지 못합니다. SaveChanges()이 실패하면 모든 문서가 추가되었지만 저장되지 않은 상태로 남아 있습니다.

나는

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

에 의해 반환 된 모든 객체를 분리하려하지만 개체가 연결되지 않는다는 내용의 예외를 얻고있다. 그렇다면 추가되었지만 저장되지 않은 모든 객체를 제거하려면 어떻게해야합니까?

+7

내가 ObjectContext는 재사용하지 않는 것이 좋습니다 것입니다. 그것이 의미가있는 시나리오가 있지만 매우 드뭅니다. ObjectContext가 사용되는 시간이 길어질수록 부풀어 오르는 시간이 길어지고 일관성없는 상태 (즉, 무언가가 부분적으로 완료 됨)가되면 부작용이 발생할 수 있습니다. –

답변

38

그냥 사소한 버그 였지만 여기서 질문을 남겨 두겠습니다. 어쩌면 다른 사람들에게 도움이됩니다. 나는 다음과 같은

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

를 원하고 그것을 볼 수 있지만

나는 다음과 같은

var objectStateEntries = this.objectContext 
          .ObjectStateManager 
          .GetObjectStateEntries(EntityState.Added); 

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

했다.

+7

제쳐두고 비트 단위의 플래그를 사용하여 var를 할 수 있습니다. objectStateEntries = this._context.ObjectStateManager .GetObjectStateEntries (EntityState.Added | EntityState.Deleted | EntityState.Modified | EntityState.Unchanged); 모든 첨부 된 개체를 분리하려면 –

+0

대답으로 표시하십시오. –

+0

어떤 경우에는'objectStateEntry.Entity'가 null이 될 것입니다 ('objectStateEntity'는 엔티티와의 관계를 설명합니다). 그래서 당신은 아마도 거기에 null 체크를 넣어야합니다. –

1

파티가 조금 늦었지만 작업 단위 패턴을 고려해 보셨습니까? 한마디로

, 그것은 당신이 다음 롤백 (폐기) 할 수있는 거래를하거나 (SaveChanges를)을 투입 할 수 있도록 할

NB : 그건 아닌 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

작업 단위 (UOW)를 사용하더라도 컨텍스트에서 오브젝트가 분리되지 않습니다. 그것은 또한 질문에 대답하지 않습니다. –

+0

@AgentShark '롤백'방법을 구현하는 방법에 전적으로 달려 있습니다. 또한, 객체를 분리하는 방법을 명시 적으로 보여주는 허용 된 대답에 올바른 코드를 복제하는 요점이 없습니다. – Basic

+0

질문을 다시 읽습니다. 작업 단위 (UOW)를 통한 강제 갱신은 유용 할 수 있습니다. 그러나 EF에서는 관련된 엔티티가있는 객체를 추가 할 때주의해야합니다. 문맥에 객체를 추가/저장하는 다른 행동을하는 다른 방법이 있습니다. –

36

다니엘의 대답은 나를 위해 일했지만 EntityFramework API는 버전 6 이상에서 다릅니다. 여기에 DbContext의 ChangeTracker에서 모든 개체를 분리합니다 나는 내 사용자 지정 저장소 컨테이너에 추가하는 방법입니다 : RC2 +엔티티 프레임 워크 코어 1.0를 사용하는 사람들을 위해

/// <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

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

가, 나는 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; 
       } 
      } 
     } 
관련 문제