Я пишу немного LINQ to SQL, который должен выполнить поиск информации о клиенте в нашей базе данных, отфильтровать результаты и разбить их на страницы. Фильтрация должна быть динамичной, поэтому я разбил настройку запроса на четыре этапа:
- Поиск видимых клиентов (в основном применяется грубый фильтр)
- Фильтр клиентов по критериям поиска
- Сортировка и просмотр клиентов
- Получить дополнительные данные клиента
Код выглядит следующим образом:
// Step 1
var visibleClientQuery = from x in xs
from y in ys
from z in yas
where
...
select new
{
id = z.Client.Id,
a = z.Client.a,
b = z.Client.e.f.g.b
};
// Step 2
if (filterByA)
{
visibleClientQuery = visibleClientQuery.Where(client => client.a > 10);
}
else
{
visibleClientQuery = visibleClientQuery.Where(client => client.b.StartsWith("ABC"));
}
// Step 3
visibleClientQuery = visibleClientQuery.Distinct();
if (filterByA)
{
visibleClientQuery = visibleClientQuery.OrderBy(client => client.a);
}
else
{
visibleClientQuery = visibleClientQuery.OrderBy(client => client.b);
}
visibleClientQuery = visibleClientQuery.Skip(50).Take(30);
// Step 4
var fullQuery = from filterClientDetail in filteredClientQuery
join client in Clients on filterClientDetail.Id equals client.Id
...;
LINQ to SQL отлично справляется с объединением этих элементов для создания эффективного запроса. Но я хочу уменьшить количество соединений, созданных в первом грубом запросе. Если я фильтрую и сортирую по A, нет необходимости для первого запроса заполнять b с помощью строки:
b = z.Client.e.f.g.b
Не заполнение b спасло бы все это дополнительное присоединение. Я попытался заменить строку на:
b = filterByA ? string.Empty : z.Client.e.f.g.b
Хотя это работает функционально, когда filterByA имеет значение true, избыточные объединения все еще присутствуют в запросе ... замедляя его. Мой обходной путь - ввести другой промежуточный запрос, который оборачивает запрос шага 1:
// Step 1
var visibleClientQuery = from x in xs
from y in ys
from z in yas
where
...
select z.Client;
// Step 2
var filteredClientQuery = from client in visibleClientQuery
select new
{
id = client.Id,
a = client.a,
b = string.Empty
};
Тогда если нам нужно отфильтровать по B, это будет заменено на:
filteredClientQuery = from client in visibleClientQuery
select new
{
id = client.Id,
a = 0,
b = client.e.f.g.b
};
Пока запрос на замену возвращает анонимный класс с теми же свойствами, это работает, но кажется ненужным, тяжелым взломом и не позволяет легко смешивать и сопоставлять фильтры ... что если нам нужно фильтровать по А и Б? В реальном запросе есть еще несколько возможных фильтров.
Есть ли способ программно изменить способ заполнения отдельного свойства в анонимном классе, возвращаемом из запроса ... во многом таким же образом, как можно изменить предложение where? С помощью FilterClientQuery.Select (...) я могу поменять весь выбор, но не вижу способа работать с отдельным свойством.
Любая помощь приветствуется ... даже если она просто подтверждает, что решения не существует!