Пытаюсь сделать LINQ запрос в котором можно менять поле (одно) по которому нужно производить сортировку. Использование переменной предиката позволяет это
public void GetMyData(string sortFieldName)
{
Func
var queryResult = db.MyEntity.OrderBy(orderPredicate);
//...some logic
}
Но резко (в десятки раз) падает производительность по сравнению с прямым заданием условия сортировки.
Насколько понимаю, должно помочь Expression. Меняю тип переменной
Expression
Но в рантайме выдаёт исключение
Не удалось привести тип "System.DateTime" к типу "System.Object". LINQ to Entities поддерживает только приведение типов-примитивов моделей EDM или типов перечисления.
Как же быть? Ведь, если я буду использовать прямое задание условия
public void GetMyData(string sortFieldName)
{
var query = db.MyEntity;
var orderedQuery = query.OrderBy(x => x.FIELD_DATE);
switch (sortFieldName)
{
case "FIELD_STRING":
orderedQuery = query.OrderBy(x => x.FIELD_STRING); break;
case "FIELD_INT":
orderedQuery = query.OrderBy(x => x.FIELD_INT); break;
case "FIELD_DATE":
orderedQuery = query.OrderBy(x => x.FIELD_DATE); break;
}
//...some logic
}
, мне будет трудно усложнить запрос дополнительными инструкциями Where, Include и т.д.
Ответ
Проблема в том, что когда вы пишите вот так:
Expression
Компилятор делает вот так:
var _param = Expression.Parameter(typeof(MyEntity), "x");
orderPredicate = Expression.Lambda
Вот на этот самый Expression.Convert EF и ругается. Для того чтобы не было преобразования - возвращаемый тип делегата обязан совпадать с типом свойства, что в свою очередь означает что общую переменную orderPredicate вы использовать не можете.
Теперь как строить такие запросы. А строятся они очень просто - через накопление IQueryable
IQueryable
Никакого усложнения тут нет, полученный запрос можно точно также дополнять другими условиями:
q = q.Where(x => x.Foo > 42);
PS поскольку у вас в параметре sortFieldName передается имя свойства, построение выражения можно еще немного упростить. Да, класс Queryable не дает нам вызвать OrderBy с неизвестным заранее именем свойства - но никто не мешает "раскрыть" этот метод и работать непосредственно с IQueryable
IQueryable
var entityParam = Expression.Parameter(typeof(MyEntity));
var propExpr = Expression.Property(entityParam, sortFieldName)
q = q.Provider.CreateQuery
Также вместо того чтобы делать это вручную - можно использовать библиотеку System.Linq.Dynamic, скачав ее из nuget:
q = q.OrderBy(sortFieldName);
Комментариев нет:
Отправить комментарий