Создание выражения Linq, динамически содержащего подзапрос - PullRequest
5 голосов
/ 03 марта 2012

Недавно я наткнулся на проблему динамического создания выражений Linq во время выполнения. Большинство примеров, которые я нашел, имеют дело с довольно простой задачей - просто сравнить одно свойство данного объекта базы данных с единственным параметром. Вот так:

 Session.Query.Where(m => m.Name.Contains("test"))

Что также может быть достигнуто с помощью гораздо более общего подхода, подобного этому:

var item = Expression.Parameter(typeof (MyClass), "item");
var property = Expression.Property(item, "Name");
var containsMethod = typeof(string).GetMethod("Contains", new[] { typeof(string) });
var searchExpression = Expression.Constant(searchString, typeof(string));
var containsMethodExpression = Expression.Call(property, containsMethod, searchExpression);
var lambda = Expression.Lambda<Func<MyClass, bool>>(containsMethodExpression, item);
query = query.Where(lambda);    

Однако иногда задача несколько сложнее, и хочется достичь чего-то вроде следующего:

Session.Query.Where(m => m.SpecialProperty.Any(f => f.Name.Contains("test")));

Где «SpecialProperty» относится к типу List <>, а свойство «Name» относится к типовой строке.

Можно ли динамически построить выражение Linq, подобное этому, и как этого достичь? Есть ли какие-либо проблемы с производительностью в отношении этого подхода?

Ответы [ 2 ]

6 голосов
/ 04 марта 2012

Нашел решение, которое работает в моем конкретном случае использования и делает именно то, что я искал.

/* 
building expression tree 
example: Session.Query.Where(m => m.SpecialProperty.Any(f => f.Name.Contains("test")))
*/ 

var innerItem = Expression.Parameter(typeof(MyInnerClass), "f");
var innerProperty = Expression.Property(innerItem, "Name");
var innerMethod = typeof(string).GetMethod("Contains", new[] { typeof(string) });
var innerSearchExpression = Expression.Constant(searchString, typeof(string));
var innerMethodExpression = Expression.Call(innerProperty, innerMethod, new[] { innerSearchExpression });
var innerLambda = Expression.Lambda<Func<MyInnerClass, bool>>(innerMethodExpression, innerItem);

var outerItem = Expression.Parameter(typeof(MyOuterClass), "m");
var outerProperty = Expression.Property(outerItem, info.Name);
/* calling a method extension defined in Enumerable */
var outerMethodExpression = Expression.Call(typeof(Enumerable), "Any", new[] { typeof(MyInnerClass) }, outerProperty, innerLambda);
var outerLambda = Expression.Lambda<Func<MyOuterClass, bool>>(outerMethodExpression, outerItem);
query = query.Where(outerLambda);

Этот довольно неуклюжий подход необходим вместо более элегантного однострочного LINQ-выражения, позволяющего параметризовать типы и имена методов.Тем не менее, я, конечно, не буду возражать против других предложений и идей о возможных потерях производительности.

Весьма вероятно, что этот фрагмент кода также может помочь в решении Как создать подзапрос с использованием не универсальной лямбды .

2 голосов
/ 03 марта 2012

Я рекомендую вам посмотреть эти ссылки:

Джозеф и Бен Албахари PredicateBuilder

Динамическая библиотека запросов LINQ

Я не пользовался какое-то время, но один или другой должен помочь.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...