Есть приложение .net + mssql и есть таблица с 50 полями и нужно сделать выборку из этой таблицы на основании фильтра который состоит из 15 параметров (поля этой таблицы)
Можно конечно сделать перебор всех параметров фильтра типа
if (filter.Param1 != null)
context.Entities.Where(a => a.Param1 = filter.Param1)
if (filter.Param2 != null)
context.Entities.Where(a => a.Param2 = filter.Param2)
Вполне нормальный вариант.
Простой в реализации, понятный в поддержке и легко расширяемый (скажем, по условиям вида !=, contains, starts with и т.п.)
Можно, конечно, заморочиться и родить что-то такое:
public static Expression<Func<Entity, bool>> BuildFilterExpression(Filter filter) {
// TODO:
// рефлексией вытягиваем из filter все не null-свойства
// и в предположении, что имя свойства в фильтре = имя свойства в Entity, собираем нужный Expression
}
// Тогда будет так:
context.Entitites.Where(BuilFilterExpression(filter))
Но городить подобное ради разовой задачи, имхо, перебор.
Здравствуйте, peer, Вы писали:
P>Привет
P>Есть приложение .net + mssql и есть таблица с 50 полями и нужно сделать выборку из этой таблицы на основании фильтра который состоит из 15 параметров (поля этой таблицы) P>Можно конечно сделать перебор всех параметров фильтра типа
P>но может есть что-то элегантнее?
если не писать context.Entities.Where 15 раз то будет уже хорошо (сделать filter.toPredicate() или типа того)
RD>Вполне нормальный вариант. RD>Простой в реализации, понятный в поддержке и легко расширяемый (скажем, по условиям вида !=, contains, starts with и т.п.)
RD>Можно, конечно, заморочиться и родить что-то такое: RD>
RD>public static Expression<Func<Entity, bool>> BuildFilterExpression(Filter filter) {
RD> // TODO:
RD> // рефлексией вытягиваем из filter все не null-свойства
RD> // и в предположении, что имя свойства в фильтре = имя свойства в Entity, собираем нужный Expression
RD>}
RD>// Тогда будет так:
RD>context.Entitites.Where(BuilFilterExpression(filter))
RD>
RD>Но городить подобное ради разовой задачи, имхо, перебор.
У нас используется второй вариант, часть которого писал я. А так я вообще за первый всегда, потому что он проще. Если лень самому писать много if, то можно попросить capilot — он накатает.
Здравствуйте, peer, Вы писали:
P>Привет
P>Есть приложение .net + mssql и есть таблица с 50 полями и нужно сделать выборку из этой таблицы на основании фильтра который состоит из 15 параметров (поля этой таблицы) P>Можно конечно сделать перебор всех параметров фильтра типа P>
Я не эксперт по EF, но код выглядит некорректным.
Вы, наверное, имели в виду что-то вроде:
var source = context.Entities;
if (filter.Param1 != null)
source = source.Where(a => a.Param1 = filter.Param1);
if (filter.Param2 != null)
source = source.Where(a => a.Param2 = filter.Param2);
...
Это вполне себе элегантно. Более элегантные вещи потребуют метапрограммирования, и оправданы тогда, когда у вас есть более-менее сложная модель. Например, у вас таких таблиц по 15 полей — много, и поддерживать вручную все вот эти N*M if (filter.StartDate != null) становится трудно. Тогда можно навелосипедить кодогенерацию, которая
1. Порождает классы фильтров для каждой Entity
2. Порождает код по генерации предиката для Entity на основе созданного для неё фильтра
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Мне такой вариант, честно говоря, не очень, даже с помощью copilot.
Ну и что делать, если появится 51-й параметр?
P>но может есть что-то элегантнее?
Почему просто не вытащить свойства filter через рефлекшен и потом собрать expression.
Я давно не писал на CSharp, но вроде как задача совсем несложная на 10-15 строчек кода?
Что-то типа:
var expressions = new List<Expression>();
var properties = filter.Type().GetProperties();
foreach prop in in properties
{
var propName = prop.Name
var propValue = prop.Value(filter);
if value != null
{
exp = Expression.Equal(
Expression.Property(prop, propName),
Expression.Constant(propValue));
expressions.add(exp);
}
}
agg = expressions.Aggregate(Expression.And);
query = query.Where(agg);
P>Почему так много полей в таблице не спрашивать)
это не много