2012-03-03 109 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」是類型列表<>和「名稱」屬性的是字符串類型。

是否有可能像這樣動態創建一個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