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

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

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

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

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

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

3 ответов


С 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 куда-то.

посмотреть мой блоге дополнительные.


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

использовать контекст.База данных.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
        } 
    } 
} 

потому что некоторая база данных может выдать исключение в dbContextTransaction.Commit () так лучше это:

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(false); 

      dbContextTransaction.Commit(); 

      context.AcceptAllChanges();
    } 
    catch (Exception) 
    { 
      dbContextTransaction.Rollback(); 
    } 
  } 
}