В любой реляционной базе данных поддержание целостности базы данных очень важно, и Транзакция является одним из способов поддержания целостности базы данных. Если у вас есть ситуация, когда вам нужно вставить данные в несколько таблиц, и если вставка данных в одну из таблиц завершается неудачно, вы должны всегда откатывать другие транзакции вставки. Тот же сценарий существует для операций обновления или удаления. Если транзакции отсутствуют, вы получите много ненужных данных в таблицах. 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. В будущем я планирую написать отдельный пост в блоге о том, как использовать существующую транзакцию с платформой сущностей.
Итак, достаточно теории, давайте создадим консольное приложение, чтобы лучше его понять.
Нам нужна Entity Framework. Поэтому я добавил его через пакет 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 для обработки любых исключений и откат транзакции. Если все пойдет хорошо, он совершит транзакцию.
Теперь давайте запустим это приложение, и следующий результат — ожидаемый результат, так как мы сгенерировали исключение.
В результате данные не были вставлены в базу данных.
Теперь давайте прокомментируем новую часть, которая вызывает исключение.
//throw new Exception("Custom Exception");
Когда мы снова запустим наше приложение, ожидаемый результат будет возвращен.
Теперь у нас есть данные в базе данных.
В результате у нас есть действительно хороший способ использовать Transaction в Entity Framework. Надеюсь, вам понравится.
Оставайтесь с нами, чтобы узнать больше!