static void SampleSaveChanges()
{
// Фабрика не предназначена для такого использования,
// но это демонстрационный код
var context = new ApplicationDbContextFactory().CreateDbContext(null);
// Внести какие-нибудь изменения.
context.<b>SaveChanges()</b>;
}
В оставшемся материале главы (и книги) вы обнаружите много примеров сохранения изменений.
Поддержка транзакций и точек сохранения
Исполняющая среда EF Core помещает каждый вызов
SaveChanges()/SaveChangesAsync()
внутрь неявной транзакции, использующей уровень изоляции базы данных. Чтобы добиться большей степени контроля, можете включить экземпляр производного класса
DbContext
в явную транзакцию. Для выполнения явной транзакции создайте транзакцию с применением свойства
Database
класса, производного от
DbContext
. Управляйте своими операциями обычным образом и затем предпримите фиксацию или откат транзакции. Ниже приведен фрагмент кода, где все демонстрируется:
using var trans = context.Database.BeginTransaction();
try
{
// Создать, изменить, удалить запись.
context.SaveChanges();
trans.Commit();
}
catch (Exception ex)
{
trans.Rollback();
}
В версии EF Core 5 были введены точки сохранения для транзакций EF Core. Когда вызывается метод
SaveChanges()/SaveChangesAsync()
, а транзакция уже выполняется, исполняющая среда EF Core создает в этой транзакции точку сохранения. Если вызов терпит неудачу, то откат транзакции происходит в точку сохранения, а не в начало транзакции. Точками сохранения можно также управлять в коде, вызывая методы
CreateSavePoint()
и
RollbackToSavepoint()
для транзакции:
using var trans = context.Database.BeginTransaction();
try
{
// Создать, изменить, удалить запись.
trans.CreateSavepoint("check point 1");
context.SaveChanges();
trans.Commit();
}
catch (Exception ex)
{
trans. RollbackToSavepoint("check point 1");
}
Транзакции и стратегии выполнения
В случае активной стратегии выполнения (как при использовании
EnableRetryOnFailure()
) перед созданием явной транзакции вы должны получить ссылку на текущую стратегию выполнения, которая применяется EF Core. Затем вызовите на этой стратегии метод
Execute()
, чтобы создать явную транзакцию:
var strategy = context.Database.CreateExecutionStrategy();
strategy.Execute(() =>
{
using var trans = context.Database.BeginTransaction();
try
{
actionToExecute();
trans.Commit();
}
catch (Exception ex)
{
trans.Rollback();
}
});
События SavingChanges/SavedChanges
В версии EF Core 5 появились три новых события, которые инициируются методами
SaveChanges()/SaveChangesAsync()
. Событие
SavingChanges
запускается при вызове
SaveChanges()
, но перед выполнением операторов SQL в хранилище данных, а событие
SavedChanges
— после завершения работы метода
SaveChanges()
. В следующем (простейшем) коде демонстрируются события и их обработчики в действии:
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
SavingChanges += (sender, args) =>
{
Console.WriteLine($"Saving changes for {((DbContext)sender).Database.
GetConnectionString()}");
};
SavedChanges += (sender, args) =>
{
Console.WriteLine($"Saved {args.EntitiesSavedCount} entities");
};
SaveChangesFailed += (sender, args) =>
{
Console.WriteLine($"An exception occurred! {args.Exception.Message}
entities");
};
}
Класс DbSet<T>
Для каждой сущности в своей объектной модели вы добавляете свойство типа
DbSet<T>
. Класс
DbSet<T>
представляет собой специализированную коллекцию, используемую для взаимодействия с поставщиком баз данных с целью получения, добавления, обновления и удаления записей в базе данных. Каждая коллекция
DbSet<T>
предлагает несколько основных служб для взаимодействия с базой данных. Любые запросы LINQ, запускаемые в отношении класса
DbSet<T>
, транслируются поставщиком базы данных в запросы к базе данных. В табл. 22.2 описан ряд основных членов класса
DbSet<T>
.