2010-03-17 12 views
42

Nesne içeriğine birkaç varlık ekliyorum. Bazı belgelerin doğrulama geçmek ve bir başarısız olursaEntity Framework nesnesinin içeriği nasıl temizlenir?

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

, doğrulama geçen tüm belgeler, nesne bağlamında ilave kalır. Nesne içeriğini temizlemek zorundayım çünkü tekrar kullanılabilir ve aşağıdakiler olabilir.

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

Bu

yüzünden yine yinelenen birincil anahtarın bir istisna durumu nesne bağlamı ve sonucu SaveChanges() doküman A ekleyecektir.

Bu nedenle, tüm yeni eklenen belgeleri bir doğrulama hatası durumunda kaldırmam gerekiyor. Tabii ki ilk önce doğrulama işlemini gerçekleştirebilirim ve başarılı bir şekilde doğrulandıktan sonra tüm belgeleri ekleyebilirim, ancak ne yazık ki bu problemi çözmez - SaveChanges() başarısız olursa, tüm belgeler yine de eklenmez ancak kaydedilmez.

Ben

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

tarafından döndürülen tüm nesneleri ayırmak çalıştım ama nesne bağlı olmadığını belirten bir istisna alıyorum. Peki, eklenen tüm ancak kaydedilmemiş nesnelerden nasıl kurtulurum?

+7

Bir ObjectContext yeniden değil öneriyoruz. Mantıklı olduğu senaryolar var ama bunlar çok nadirdir. Bir ObjectContext'in ne kadar çok şişirilmiş olduğunu kullandığını ve eğer tutarsız bir duruma girerse (yani, bir şeyler kısmen yapılırsa), bazı tutarsız yan etkilere de sahip olabileceğinizi unutmayın. –

cevap

38

Sadece önemsiz bir hataydı ama ben buradaki soruyu bırakıyorum - belki başkalarına yardım eder. Aşağıdaki

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

istediğini ve bunu göremiyordu ise

aşağıdaki

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

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

vardı.

+7

Bir kenara göre var objectStateEntries = this._context.ObjectStateManager .GetObjectStateEntries (EntityState.Added | EntityState.Deleted | EntityState.Modified | EntityState.Unchanged); Tüm ekli nesneleri çıkartmak için –

+0

Yanıt olarak işaretle. –

+0

Bazı durumlarda, 'objectStateEntry.Entity' öğesinin boş olacağına dikkat edin ('objectStateEntity' hiçbir varlıktan bir ilişkiyi açıklar), bu nedenle muhtemelen bir null check in oraya koymalısınız. –

1

Partiye biraz geç kaldınız ama bir birim iş modelini düşündünüz mü? Kısacası

, bu daha sonra geri alma (elden) olabilecek bir işlem varsa veya (SaveChanges) işlemek için izin verecek

Not: Bu bir sql olduğu gibi, bir faaliyete değişikliklerin gruplaşma olduğu gibi işlem var BAŞLI TRAN. Bu hala sizin için SaveChanges() yöntemi tarafından ele alınmıştır.

şey gibi:

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 

Eğer işin bir birimi oluşturmak her zaman, bir ObjectContext alır - eskisi olduysa Biz yenisi oluşturulur, böylece bu oluşturmak için Unity kullanıyorsanız imhası

+2

Bir çalışma birimi kullanmak, yine de nesneleri bağlamdan ayırmaz. Aynı zamanda soruya cevap vermiyor. –

+0

@AgentShark Tamamen 'Geri Alma' yönteminizi nasıl uyguladığınıza bağlıdır. Ayrıca, kabul edilen yanıtta doğru kodu çoğaltmanın bir anlamı yoktur, bu da nesnelere nasıl ayrılacağını açıkça gösterir. – Basic

+0

Soruyu tekrar okudum. Evet, bir iş birimi aracılığıyla güncellemeleri zorlamak yararlı olacaktır. Ancak EF'de, ilgili varlıklarla nesne eklerken dikkatli olmanız gerekir. İçeriğe nesne eklemek/kaydetmek için farklı davranışlarda farklı yollar vardır. –

36

Daniel'in cevabı benim için çalıştı, ancak EntityFramework API'si 6+ sürümde farklı. İşte DBContext en ChangeTracker tüm varlıkları ayırmak olacaktır benim özel depo kabına ilave edilen bir yöntemdir: RC2 +Varlık Framework Çekirdek 1.0 kullananlar için

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

Bu yöntem benim için çalışıyor: -D teşekkürler! – duardbr

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

, ben Garrys' cevabını güncellendi.

Referans

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

Güncelleme kod

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