Откат транзакции Entity Framework 6

c# entity-framework entity-framework-6 sql-server transactions

Вопрос

С EF6 у вас есть новая транзакция, которая может использоваться как:

using (var context = new PostEntityContainer())
        {
            using (var dbcxtransaction = context.Database.BeginTransaction())
            {
                try
                {
                    PostInformation NewPost = new PostInformation()
                    {
                        PostId = 101,
                        Content = "This is my first Post related to Entity Model",
                        Title = "Transaction in EF 6 beta"
                    };
                    context.Post_Details.Add(NewPost);
                    context.SaveChanges();
                    PostAdditionalInformation PostInformation = new PostAdditionalInformation()
                    {
                        PostId = (101),
                        PostName = "Working With Transaction in Entity Model 6 Beta Version"
                    };

                    context.PostAddtional_Details.Add(PostInformation);
                    context.SaveChanges();

                    dbcxtransaction.Commit();
                }
                catch
                {
                    dbcxtransaction.Rollback();
                }
            }
        }

Действительно ли откат необходим, когда все идет боком? Мне любопытно, потому что в описании Commit сказано: «Выполняет основную транзакцию хранилища».

Если в описании Rollback указано: «Откат основной транзакции магазина».

Мне это любопытно, потому что мне кажется, что если Commit не вызывается, ранее выполненные команды не будут сохранены (что кажется мне логичным). Но если это так, то зачем было бы называть функцию отката? В EF5 я использовал TransactionScope, у которого не было функции Rollback (только Complete), которая казалась мне логичной. Из-за причин MS DTC я больше не могу использовать TransactionScope, но я также не могу использовать try catch, как в примере выше (т.е. мне нужен только Commit).

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

Вам не нужно вызывать Rollback вручную, потому что вы используете оператор using .

Метод DbContextTransaction.Dispose будет вызываться в конце блока using . И он автоматически откатит транзакцию, если транзакция не будет успешно выполнена (не вызванные или обнаруженные исключения). Ниже приведен исходный код метода SqlInternalTransaction.Dispose ( DbContextTransaction.Dispose , наконец, делегирует его при использовании поставщика SqlServer):

private void Dispose(bool disposing)
{
    // ...
    if (disposing && this._innerConnection != null)
    {
        this._disposing = true;
        this.Rollback();
    }
}

Понимаете, он проверяет, не является ли _innerConnection недействительным, если нет, отката транзакции (если она была зафиксирована, _innerConnection будет null). Давайте посмотрим, что делает Commit :

private void Dispose(bool disposing)
{
    // ...
    if (disposing && this._innerConnection != null)
    {
        this._disposing = true;
        this.Rollback();
    }
}

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

До тех пор, пока вы всегда будете использовать SQL Server с EF, нет необходимости явно использовать catch для вызова метода Rollback. Разрешить использование блока автоматически откат при любых исключениях всегда будет работать.

Однако, когда вы думаете об этом с точки зрения Entity Framework, вы можете понять, почему все примеры используют явный вызов для отмены транзакции. Для EF поставщик базы данных произволен и подключается, и поставщик может быть заменен на MySQL или любую другую базу данных, имеющую реализацию поставщика EF. Поэтому, с точки зрения EF, нет гарантии, что поставщик автоматически откатится от удаленной транзакции, потому что EF не знает о реализации поставщика базы данных.

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

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




Лицензировано согласно: CC-BY-SA with attribution
Не связан с Stack Overflow
Является ли этот КБ законным? Да, узнайте, почему
Лицензировано согласно: CC-BY-SA with attribution
Не связан с Stack Overflow
Является ли этот КБ законным? Да, узнайте, почему