TGViewer
.NET Разработчик .NET Разработчик @netdeveloperdiary · 6.77K subscribers
Post #1915 1.63K
День 1569. #ЗаметкиНаПолях
Избегайте Распространения DbContext или IQueryable в Приложениях. Начало
Большинство приложений .NET используют EF Core и DbContext для доступа к данным, но удобство сопровождения может пострадать, если использование DbContext или производного от него IQueryable распространяется по всему приложению.

Интерфейсы IQueryable и IQueryable<T> в .NET позволяют описывать запросы в виде деревьев выражений, которые при выполнении преобразуются провайдером в запросы к БД. В EF IQueryable используется, чтобы создавать динамические SQL-запросы, что позволяет выполнять детальные и эффективные запросы к базе данных, а не извлекать больше данных, чем необходимо, в память приложения, а затем фильтровать результат в памяти.

Ниже создаётся набор заказов, отфильтрованных по дате. В первом примере все заказы из БД передаются в приложение, а затем фильтруются. Во втором используется динамический SQL-запрос, позволяющий БД возвращать только совпадающие записи:
var since = new DateTime(2023,1,1);

// фильтрация в памяти
var all = dbContext.Orders.ToList();
var recent1 = all
.Where(o.Date > since)
.ToList();

// фильтрация в БД
var recent2 = dbContext.Orders
.Where(o.Date > since)
.ToList();

Очевидно, что скорость и эффективность второго подхода почти всегда делают его предпочтительным методом.

Можно создать выражение IQueryable с помощью серии операторов, даже в разных функциях, классах или проектах. Когда об этом было впервые объявлено, в Microsoft высоко оценили эту возможность, т.к. разработчики могли создавать нужный запрос «по требованию», где бы им это ни требовалось, гарантируя, что при окончательном выполнении запроса будут возвращены только необходимые данные. У вас может быть сервис, возвращающий «чистые» данные:
public class DataService
{
public async
Task<IQueryable<Order>> List()
{
return await
_dbContext.Orders.AsQueryable();
}
}

Сервис бизнес-логики, который накладывает некоторые ограничения на выборку:
public class OrderService
{
// сервис данных внедряется в _dataService
public async
Task<IQueryable<Order>> ActiveOrders()
{
var all = await _dataService.List();
return await all
.Where(o => !o.Canceled)
.AsQueryable();
}
}

Затем в контроллере добавляется фильтр текущего пользователя:
var viewModel =
await _orderSvc.ActiveOrders()
.Where(o => o.CreatedBy = username)
.AsQueryable();

Наконец, на странице в коде Razor мы генерируем окончательный список:
foreach(var ord in
model.Orders.Where(o => o.Shipped()))
{
// список в HTML
}

В итоге у нас получается следующий запрос, который будет выполнен:
_dbContext.Orders
.Where(o => !o.Canceled &&
o.CreatedBy == username &&
o.Shipped);

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

Окончание следует…

Источник:
https://ardalis.com/avoid-dbcontext-iqueryable-proliferation/
  • 👍 15
More from @netdeveloperdiary
  1. Oct 11, 2026День 2811. #ВопросыНаСобеседовании Марк Прайс предложил свой набор из 60 вопросов (как тех…
  2. Oct 10, 2026День 2810. #ЧтоНовенького #VSCode Более Быстрый и Лёгкий C# Dev Kit Мы, разработчики, люби…
  3. Oct 9, 2026День 2809. #Карьера 5 Навыков, Которые Помогут Быстрее Стать Сеньором. Окончание Начало 3.…
  4. Oct 8, 2026День 2808. #Карьера 5 Навыков, Которые Помогут Быстрее Стать Сеньором. Начало В ИТ есть се…
  5. Oct 7, 2026День 2807. #ЗаметкиНаПолях Типы Коллекций в .NET, Которые Стоит Попробовать. Окончание Нач…
  6. Oct 6, 2026🦈 Открытое собеседование на Middle C# | 6 октября, 19:00 МСК Приглашаем на открытое собес…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →