Используя транзакции или SaveChanges (false) и AcceptAllChanges ()?

c# entity-framework transactions

Вопрос

Я исследовал транзакции, и кажется, что они заботятся о себе в EF, пока я передаю false в SaveChanges() и затем вызываю AcceptAllChanges() если нет ошибок:

SaveChanges(false);
// ...
AcceptAllChanges();

Что если что-то пойдет не так? мне не нужно откатывать или, как только мой метод выходит из области видимости, транзакция заканчивается?

Что происходит с какими-либо столбцами отступов, которые были назначены на полпути через транзакцию? Я предполагаю, что если кто-то еще добавил запись после моей, прежде чем моя испортилась, это означает, что будет отсутствовать значение Identity.

Есть ли причина использовать стандартный класс TransactionScope в моем коде?

Принятый ответ

С Entity Framework большую часть времени достаточно SaveChanges() . Это создает транзакцию или участвует в любой внешней транзакции и выполняет всю необходимую работу в этой транзакции.

Иногда, хотя спаривание SaveChanges(false) + AcceptAllChanges() полезно.

Самое полезное место для этого - ситуации, когда вы хотите выполнить распределенную транзакцию в двух разных контекстах.

Т.е. как то так (плохо)

using (TransactionScope scope = new TransactionScope())
{
    //Do something with context1
    //Do something with context2

    //Save and discard changes
    context1.SaveChanges();

    //Save and discard changes
    context2.SaveChanges();

    //if we get here things are looking good.
    scope.Complete();
}

Если context1.SaveChanges() завершается успешно, но context2.SaveChanges() завершается неудачно, вся распределенная транзакция прерывается. Но, к сожалению, Entity Framework уже отменил изменения в context1 , поэтому вы не можете воспроизвести или эффективно зарегистрировать ошибку.

Но если вы измените свой код, чтобы он выглядел так:

using (TransactionScope scope = new TransactionScope())
{
    //Do something with context1
    //Do something with context2

    //Save Changes but don't discard yet
    context1.SaveChanges(false);

    //Save Changes but don't discard yet
    context2.SaveChanges(false);

    //if we get here things are looking good.
    scope.Complete();
    context1.AcceptAllChanges();
    context2.AcceptAllChanges();

}

В то время как вызов SaveChanges(false) отправляет необходимые команды в базу данных, сам контекст не изменяется, поэтому вы можете сделать это снова, если необходимо, или вы можете ObjectStateManager если хотите.

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

Смотрите мой блог для получения дополнительной информации.


Популярные ответы

Если вы используете EF6 (Entity Framework 6+), это изменилось для вызовов базы данных в SQL.
См .: http://msdn.microsoft.com/en-us/data/dn456843.aspx

использовать context.Database.BeginTransaction.

Из MSDN:

using (var context = new BloggingContext()) 
{ 
    using (var dbContextTransaction = context.Database.BeginTransaction()) 
    { 
        try 
        { 
            context.Database.ExecuteSqlCommand( 
                @"UPDATE Blogs SET Rating = 5" + 
                    " WHERE Name LIKE '%Entity Framework%'" 
                ); 

            var query = context.Posts.Where(p => p.Blog.Rating >= 5); 
            foreach (var post in query) 
            { 
                post.Title += "[Cool Blog]"; 
            } 

            context.SaveChanges(); 

            dbContextTransaction.Commit(); 
        } 
        catch (Exception) 
        { 
            dbContextTransaction.Rollback(); //Required according to MSDN article 
            throw; //Not in MSDN article, but recommended so the exception still bubbles up
        } 
    } 
} 


Related

Лицензировано согласно: CC-BY-SA with attribution
Не связан с Stack Overflow
Лицензировано согласно: CC-BY-SA with attribution
Не связан с Stack Overflow