2012-03-03 5 views
5

Gần đây, tôi đã gặp phải sự cố khi tạo động các biểu thức LINQ trong thời gian chạy. Hầu hết các ví dụ tôi tìm thấy đối phó với các nhiệm vụ khá đơn giản chỉ cần so sánh một tài sản của một thực thể cơ sở dữ liệu nhất định với một tham số duy nhất. Cũng giống như vậy:Tạo biểu thức LINQ có chứa truy vấn phụ

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

nào cũng có thể đạt được với một cách tiếp cận chung chung hơn như thế này:

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);  

Tuy nhiên, đôi khi nhiệm vụ có phần phức tạp hơn và ai muốn đạt được một cái gì đó như sau:

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

Trường hợp "SpecialProperty" thuộc loại Danh sách <> và thuộc tính "Tên" thuộc loại chuỗi.

Có thể xây dựng một biểu thức LINQ như thế này một cách năng động và làm cách nào để đạt được điều này? Có bất kỳ mối lo ngại về hiệu suất nào liên quan đến cách tiếp cận này không?

Trả lời

6

Tìm thấy giải pháp đang hoạt động trong trường hợp sử dụng cụ thể của tôi và thực hiện chính xác những gì tôi đang tìm kiếm.

/* 
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); 

Phương pháp này khá cần thiết thay vì dòng LINQ-Expression thanh lịch hơn để cho phép tham số các loại và tên phương thức. Tuy nhiên, tôi tất nhiên sẽ không nhớ các đề xuất và ý tưởng khác về các hình phạt hiệu suất có thể có.

Rất có thể đoạn mã này cũng có thể hỗ trợ giải quyết How to produce a Subquery using non-generic Lambda.

2

tôi khuyên bạn nên nhìn vào những liên kết này:

Joseph và Ben Albahari của PredicateBuilder

Các LINQ dynamic query library

Tôi đã không được sử dụng hoặc một thời gian, nhưng cái này hay cái khác nên giúp đỡ.