Статьи

Работа с транзакциями в Entity Framework 6

В любой реляционной базе данных поддержание целостности базы данных очень важно, и Транзакция является одним из способов поддержания целостности базы данных. Если у вас есть ситуация, когда вам нужно вставить данные в несколько таблиц, и если вставка данных в одну из таблиц завершается неудачно, вы должны всегда откатывать другие транзакции вставки. Тот же сценарий существует для операций обновления или удаления. Если транзакции отсутствуют, вы получите много ненужных данных в таблицах. Entity Framework является одним из самых популярных ORM в .NET World. Итак, в этом посте мы узнаем, как мы можем использовать транзакции с Entity Framework 6. 

Транзакция и Entity Framework 6

Entity Framework внутренне поддерживает транзакцию при вызове метода SaveChanges (). Таким образом, все операции вставки и обновления при одном вызове метода сохранения изменений будут выполняться в одной транзакции. Но если вы хотите обернуть несколько методов SaveChanges () в одну транзакцию, в более ранних версиях Entity Framework нет встроенных функций. 

Теперь, с Entity Framework 6.0, у нас есть два встроенных API для транзакций:

DbContext.Database.BeginTransaction

Этот вызов API позволит нам начать транзакцию для нескольких изменений сохранения. Вы можете объединить столько операций, сколько вы хотите в одной транзакции, и, следовательно, либо все они будут выполнены успешно, то транзакция будет зафиксирована. Если произойдет какое-либо исключение, транзакция будет отменена.

DbContext.Database.UseTransaction

Иногда нам нужно использовать транзакцию, которая запускается вне рамок сущности. В этом случае этот вызов API позволяет нам также использовать эту транзакцию с Entity Framework. 

В этом сообщении мы будем использовать Begin Transaction. В будущем я планирую написать отдельный пост в блоге о том, как использовать существующую транзакцию с платформой сущностей.

Итак, достаточно теории, давайте создадим консольное приложение, чтобы лучше его понять.

EF6-с-транзакция-консольное приложение Нам нужна Entity Framework. Поэтому я добавил его через пакет nuget.

сущность-рамка-транзакции NuGet-пакет

В этом приложении мы собираемся использовать два модельных класса, называемые категорией и продуктом. Мы сохраним их обе в одной транзакции и попытаемся понять, как транзакция работает с Entity Framework.

Модель категории указана ниже:

namespace EFWithTransactions
{
    public class Category
    {
        public int CategoryId { get; set; }
        public string CategoryName { get; set; }
    }
}

Вот модель продукта:

using System.ComponentModel.DataAnnotations.Schema;

namespace EFWithTransactions
{
    public class Product
    {
        public int ProductId { get; set; }
        public string ProductName { get; set; }
        [ForeignKey("Category")]
        public int CategoryId { get; set; }
        public virtual Category Category { get; set; }
    }
}

Здесь вы можете видеть, что у меня есть идентификатор категории в продукте, к которому относится продукт. Я создал свой класс dbcontext, как показано ниже:

using System.Data.Entity;

namespace EFWithTransactions
{
    public class ProductDbContext : DbContext
    {
        public ProductDbContext()
            : base("ProductConnectionString")
        {

        }
        public DbSet<Category> Categories { get; set; }
        public DbSet<Product> Products { get; set; }
    }
}

Метод Main консольного приложения показан ниже, который иллюстрирует реальный сценарий, когда исключение может произойти во время нескольких изменений сохранения ().

using System;

namespace EFWithTransactions
{
    class Program
    {
        static void Main(string[] args)
        {
            using (ProductDbContext productDbContext = new ProductDbContext())
            {
                using (var transaction = productDbContext.Database.BeginTransaction())
                {
                    try
                    {
                        //saving category
                        Category category = new Category
                        {
                            CategoryName = "Clothes"
                        };
                        productDbContext.Categories.Add(category);
                        productDbContext.SaveChanges();

                        // Throw some error to check transaction
                        // Comment this to make transactions sucessfull
                        // throw new Exception("Custom Exception");

                        //saving product
                        Product product = new Product
                        {
                            ProductName = "Blue Denim Shirt",
                            CategoryId = category.CategoryId
                        };
                        productDbContext.Products.Add(product);
                        productDbContext.SaveChanges();
                        Console.Write("Cateogry and Product both saved");
                        transaction.Commit();
                    }
                    catch (Exception exception)
                    {
                        transaction.Rollback();
                        Console.WriteLine("Transaction Roll backed due to some exception");
                    }
                }

            }
            Console.ReadKey();
        }
    }
}

Если вы внимательно изучите приведенный выше код, вы увидите, что у меня есть два метода сохранения изменений: один для категории и другой для продукта. Я также использовал метод BeginTransaction для запуска новой транзакции.

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

Теперь давайте запустим это приложение, и следующий результат — ожидаемый результат, так как мы сгенерировали исключение.

Транзакция-откат-сущность-рамка

В результате данные не были вставлены в базу данных.

SQL-сервер баз данных с-не-данных

Теперь давайте прокомментируем новую часть, которая вызывает исключение.

//throw new Exception("Custom Exception");

Когда мы снова запустим наше приложение, ожидаемый результат будет возвращен.

транзакции совершенные-SQL-сервер

Теперь у нас есть данные в базе данных.

SQL-сервер базы данных с-данные транзакций поручены

В результате у нас есть действительно хороший способ использовать Transaction в Entity Framework. Надеюсь, вам понравится.

Оставайтесь с нами, чтобы узнать больше!