TGViewer
.NET Разработчик .NET Разработчик @netdeveloperdiary · 6.75K subscribers
Post #2964 2.52K
День 2463. #ЗаметкиНаПолях
Динамический LINQ. Окончание

Начало

2. OrderByDynamic/ThenByDynamic
Даём пользователю возможность отсортировать результаты по любой колонке (из белого списка).
var sort = sortCol switch
{
"LastLogon" => "x => x.LastLogon",
"TotalSpent" => "x => x.TotalSpent",
_ => "x => x.Name"
};

var ordered = await context.Customers
.OrderByDynamic(sort)
.ThenByDynamic("x => x.Id")
.ToListAsync();


3. SelectDynamic
Для сценариев отчётов/экспорта, выдаём только то, что запросил клиент:
// Клиент выбрал: "Id,Name,Country"
var cols = selectedCols.Split(',')
.Select(c => c.Trim())
.Where(c => allowedCols.Contains(c));

var selectExpr = "x => new { "
+ string.Join(", ", cols.Select(c => $"{c} = x.{c}"))
+ " }";

var result = await context.Customers
.WhereDynamic("x => x.Status == 0")
.SelectDynamic(selectExpr)
.ToListAsync();


4. FirstOrDefaultDynamic
Идеален для поиска одного элемента или валидации на основе критерия, определяющегося во время выполнения:
csharp 
var result = await context.Customers
.FirstOrDefaultDynamic(
"x => x.Email == \\\"name@mail.com\\\" && x.Status == 0");


Бонус: Цепочки динамических конвейеров
Если очень нужно выполнить несколько шагов LINQ в одной динамической строке (фильтрация → упорядочивание → выборка → список), есть API Execute:
var env = new { 
IsActive = CustomerStatus.IsActive,
LastMonth = DateTime.Now.AddMonths(-1) };

var result = context.Customers.Execute<IEnumerable>(
"Where(x => x.Status == IsActive && x.LastLogon >= LastMonth)" +
".Select(x => new { x.CustomerID, x.Name })" +
".OrderBy(x => x.CustomerID).ToList()", env);

Это мощный метод, но код получается не особо читаемый.

Варианты использования
1. Администрирование «Конструктор запросов»
- UI генерирует: поле + оператор + значение;
- Бэкенд выбирает разрешённые поля/операции → строит WhereDynamic (и опционально OrderByDynamic);
- Результат: один конвейер запросов, почти бесконечное количество комбинаций.

2. Маркетинг «Конструктор сегментов»
- Сегменты сохраняются как читаемые выражения (например, «Активные, последние 90 дней,>$500,не тестовые аккаунты»);
- Приложение загружает правило → WhereDynamic → сохраняет результаты;
- Результат: правила развиваются без изменения кода или повторного развёртывания.

3. Многопользовательские правила
- Каждый пользователь хранит несколько предикатов (или базовых фильтров разрешения/запрета);
- Они комбинируются во время запроса и применяются динамически;
- Результат: меньше ветвлений/флагов, более чистая модель.

Замечания
- Белый список полей/операторов: не раскрывайте всю модель; предоставьте в UI только разрешённый список.
- Проверка выражений: отклоняйте неизвестные токены/поля перед выполнением.
- IQueryable до конца: применяйте динамические операции перед ToList(), чтобы EF мог преобразовать их в SQL.
- Нормализуйте значения: используйте даты ISO или параметры (объект env) вместо парсинга текста.
- Сохраняйте читаемость: предпочитайте короткие, компонуемые строки; добавляйте вспомогательные методы для частых случаев.

Когда не использовать
Если у вас 2-3 фиксированных фильтра, которые редко меняются, статический LINQ остается самым простым (и вполне приемлемым). Динамический LINQ имеет смысл при росте изменчивости и опциональности.

Источник:
https://thecodeman.net/posts/dynamic-linq-in-dotnet
  • 👍 7
  • 👎 1
More from @netdeveloperdiary
  1. Sep 30, 2026Post #3356
  2. Sep 29, 2026Фото 3 (с) Анатолий Кулаков
  3. Sep 29, 2026День 2799. Конференция DotNext 2026. Часть 1 25 и 26 сентября в Москве прошла очередная ко…
  4. Sep 28, 2026День 2798. #Оффтоп Утиная Типизация в C# с Помощью Перехватчиков. Часть 2 Некоторое время…
  5. Sep 27, 2026День 2797. #ЗаметкиНаПолях #AI Рабочий процесс с Copilot для .NET. Окончание Начало Продол…
  6. Sep 26, 2026День 2796. #ЗаметкиНаПолях #AI Рабочий процесс с Copilot для .NET. Продолжение Начало Три…
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 →