动态构建查询

问题描述:

嗨,感谢您花时间回答我的问题。动态构建查询

在与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

是的,这是可能的。最简单的方法是用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属性... –

要做到这一点最简单的方法是编写两个查询,即

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

在这篇文章中,你可以找到一些有用的扩展方法,可以让你谓词结合(它应该工作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); 
}