2012-03-03 2 views
5

Недавно я столкнулся с проблемой динамического создания выражений Linq во время выполнения. Большинство примеров, которые я нашел, касаются довольно простой задачи просто сравнить одно свойство данного объекта базы данных с одним параметром. Как так:Создание выражения 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» находится в списке типов <> и свойство «Name» имеет тип строки.

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

ответ

6

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

/* 
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-выражения для обеспечения параметризации типов и имен методов. Однако я, конечно, не возражал бы против других предложений и идей относительно возможных штрафов за производительность.

Весьма вероятно, что этот фрагмент кода также может помочь в решении How to produce a Subquery using non-generic Lambda.

2

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

Джозеф и Бен Albahari-х PredicateBuilder

LINQ dynamic query library

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

Смежные вопросы