Подтвердить что ты не робот

Как очистить объект объекта 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)

но я получаю исключение, заявляя, что объект не подключен. Итак, как мне избавиться от всех добавленных, но несохраненных объектов?

4b9b3361

Ответ 1

Это была всего лишь тривиальная ошибка, но я собираюсь оставить вопрос здесь - возможно, это помогает другим.

У меня было следующее

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

Ответ Даниэля сработал для меня, однако API-интерфейс EntityFramework отличается в версии 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().ToArray()) {

            if (dbEntityEntry.Entity != null) {
                dbEntityEntry.State = EntityState.Detached;
            }
        }
    }

Ответ 3

Немного поздно для вечеринки, но вы считали шаблон Unit of Work?

Короче говоря, это позволит вам иметь транзакцию, которую вы могли бы откат (распоряжаться) или совершить (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

Каждый раз, когда вы создаете единицу работы, он принимает объект contexttext. Мы используем Unity для их создания, чтобы новый был создан, если старый был удален

Ответ 4

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

Ответ 5

Для тех, кто использует Entity Framework Core 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;
                }
            }
        }