Полезные Функции EF Core. Начало
EF Core – мощный инструмент, и знание нескольких ключевых функций может сэкономить вам много времени и избежать разочарований.
1. Разделение запросов
Функция которая нужна редко, но, когда требуется, приходится очень кстати. Разделение запросов полезно в сценариях, где вы ждёте загрузки из нескольких коллекций. Она помогает избежать проблемы декартового взрыва.
Допустим, вы хотите получить отдел со всеми командами, сотрудниками и их задачами:
List<Department> departments =
context.Departments
.Include(d => d.Teams)
.ThenInclude(t => t.Employees)
.ThenInclude(e => e.Tasks)
.ToList();
Это преобразуется в один SQL-запрос с несколькими JOIN. Предположим, что в отделе много команд, а в каждой команде много сотрудников. В этом случае БД возвращает много строк из каждого подзапроса, что значительно влияет на производительность. Вот как можно избежать этих проблем с производительностью с помощью разделения запросов:
List<Department> departments =
context.Departments
.Include(d => d.Teams)
.ThenInclude(t => t.Employees)
.ThenInclude(e => e.Tasks)
.AsSplitQuery()
.ToList();
При использовании AsSplitQuery EF Core будет выполнять дополнительный SQL-запрос для каждого навигационного свойства коллекции. Однако не злоупотребляйте разделением запросов. Измерьте производительность в каждом случае для вашего конкретного набора данных. Разделённые запросы делают больше обращений к БД, что может быть медленнее, если задержка базы данных высока. Также нет гарантии согласованности между несколькими SQL-запросами.
См. подробнее о разделённых запросах.
2. Массовые обновления и удаления
EF Core 7 добавил два новых API для выполнения массовых обновлений и удалений, ExecuteUpdate и ExecuteDelete. Они позволяют эффективно обновлять большое количество строк за один цикл обращения к БД.
Например, компания решила повысить зарплату на 5% всем сотрудникам в отделе «Продажи». Мы могли бы пройтись по всем сотрудникам и обновить их зарплату:
var salesEmployees = context.Employees
.Where(e => e.Department == "Sales")
.ToList();
foreach (var employee in salesEmployees)
employee.Salary *= 1.05m;
context.SaveChanges();
Этот подход приведёт к множеству запросов в БД, что может быть неэффективным, особенно для больших наборов данных. Мы можем добиться того же за один запрос, используя ExecuteUpdate:
context.Employees
.Where(e => e.Department == "Sales")
.ExecuteUpdate(s =>
s.SetProperty(e => e.Salary, e => e.Salary * 1.05m));
Это приведёт к одному SQL-запросу UPDATE, и прямому изменению зарплаты в БД без загрузки сущностей в память.
Ещё пример. Допустим, платформа электронной коммерции хочет удалить все корзины покупок старше года:
context.Carts
.Where(o => o.CreatedOn < DateTime.Now.AddYears(-1))
.ExecuteDelete();
Однако массовые обновления обходят трекер изменений EF. Это может быть проблемой, о чём см. подробнее.
Окончание следует…
Источник: https://www.milanjovanovic.tech/blog/5-ef-core-features-you-need-to-know