2012-12-05 92 views
1

嗨,感謝您花時間回答我的問題。動態構建查詢

在與Java合作一年半後,我決定切換回.NET。我必須說,我在VS2012中感到賓至如歸。

在使用Java時,我遇到了一個hibernate的實現,可以輕鬆創建動態查詢。

想象一下,我有一個帶有5個字段的表單,其中只有一個,任何一個必須填充以便我過濾結果。

是有辦法,我可以做在C#中的以下內容:

if(txtMunicipality.text.length > 0){ 
    (x => x.municipality == txtMunicipality.text) 
} 

if(chkboxIsFinished){ 
    (x => x.isfinished == true) 
} 

等。

所以我C檢查每個字段,如果已被填充,則該值添加標準查詢..和我完成後,我執行查詢檢查。有沒有辦法在C#中做到這一點?

+0

可能是:http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query -library.aspx – Habib

+0

我認爲這個問題不是關於動態LINQ,而是動態構建查詢。 –

+0

是的,你是對的..我會編輯我的文章 – Dragan

回答

1

是的,這是可能的。最簡單的方法是用delegates,尤其是匿名的。

例如:

Func<YourEntity, bool> filter = (_ => true); // Default value. 

if (txtMunicipality.text.length > 0) 
{ 
    filter = (x => x.municipality == txtMunicipality.text); 
} 
else if (chkboxIsFinished) 
{ 
    filter = (x => x.isfinished == true); 
} 

然後你就可以在Where語句中使用filter代表在查詢中,例如(我想是你的意圖 - 如果沒有,例如仍然適用,只是不直接適用)

/ LINQ syntax. 
var entities = from e in context 
       where filter(e) 
       select e; 

// Method syntax. 
var entities = context.Where(x => filter(x)); 
// Or simply: 
var entities = context.Where(filter); 
+0

'context.Where'版本使用委託會真的***壞,如果這個'context'實際上是EF/L2S/NH等;它會在.NET端而不是在原點進行過濾。 –

+0

嗯,你是對的,我有時會忘記IQueryable屬性... –

2

要做到這一點最簡單的方法是編寫兩個查詢,即

IQueryable<Foo> query = ... // or possibly IEnumerable<Foo> 
if(!string.IsNullOrEmpty(txtMunicipality.text)) { 
    query = query.Where(x => x.municipality == txtMunicipality.text); 
} 
if(chkboxIsFinished) { 
    query = query.Where(x.isfinished); 
} 

可以也直接組成表達式樹和委託;如果您需要,請指出您擁有的:表達式樹與委託。


編輯:這裏是你會怎麼做,構成表達而不是查詢:

static class Program 
{ 
    static void Main() 
    { 
     Expression<Func<int, bool>> exp1 = x => x > 4; 
     Expression<Func<int, bool>> exp2 = x => x < 10; 
     Expression<Func<int, bool>> exp3 = x => x == 36; 

     var combined = (exp1.AndAlso(exp2)).OrElse(exp3); 
     // ^^^ equiv to x => (x > 4 && x < 10) || x == 36 
    } 
    static Expression<Func<T, bool>> OrElse<T>(this Expression<Func<T, bool>> x, Expression<Func<T, bool>> y) 
    { // trivial cases 
     if (x == null) return y; 
     if (y == null) return x; 

     // rewrite using the parameter from x throughout 
     return Expression.Lambda<Func<T, bool>>(
      Expression.OrElse(
       x.Body, 
       SwapVisitor.Replace(y.Body, y.Parameters[0], x.Parameters[0]) 
      ), x.Parameters); 
    } 
    static Expression<Func<T, bool>> AndAlso<T>(this Expression<Func<T, bool>> x, Expression<Func<T, bool>> y) 
    { // trivial cases 
     if (x == null) return y; 
     if (y == null) return x; 

     // rewrite using the parameter from x throughout 
     return Expression.Lambda<Func<T, bool>>(
      Expression.AndAlso(
       x.Body, 
       SwapVisitor.Replace(y.Body, y.Parameters[0], x.Parameters[0]) 
      ), x.Parameters); 
    } 
    class SwapVisitor : ExpressionVisitor 
    { 
     public static Expression Replace(Expression body, Expression from, Expression to) 
     { 
      return new SwapVisitor(from, to).Visit(body); 
     } 
     private readonly Expression from, to; 
     private SwapVisitor(Expression from, Expression to) 
     { 
      this.from = from; 
      this.to = to; 
     } 
     public override Expression Visit(Expression node) 
     { 
      return node == from ? to : base.Visit(node); 
     } 
    } 
} 
1

在這篇文章中,你可以找到一些有用的擴展方法,可以讓你謂詞結合(它應該工作NHibernate的爲好):

LINQ to Entities: Combining Predicates

你可以再建一個拉姆達表達這樣的:

Expression<Func<MyObject, bool>> predicate = x => true; 

if(txtMunicipality.text.length > 0){ 
    predicate = predicate.And(x => x.municipality == txtMunicipality.text); 
} 

if(chkboxIsFinished){ 
    predicate = predicate.And(x => x.isfinished == true); 
}