冬Blog

醉心技术、醉心生活
  博客园  :: 首页  :: 新随笔  :: 订阅 订阅  :: 管理

也说Linq动态条件查询

Posted on 2007-07-17 11:24  冬冬  阅读(5423)  评论(5编辑  收藏  举报

 1,构造表达式树

    private Expression<Func<Blog, bool>> getCondition()
    
{
        Expression
<Func<Blog, bool>> expression = blog => true;

        
if (!String.IsNullOrEmpty(Request["BlogClassID"]))
        
{
            
int blogClassID;
            
if (Int32.TryParse(Request["BlogClassID"], out blogClassID))
            
{
                Expression
<Func<Blog, bool>> e2 = blog => blog.BlogClass == null;
                var invokedExpr 
= Expression.Invoke(e, expression.Parameters.Cast<Expression>());

                expression 
= Expression.Lambda<Func<Blog, bool>>(Expression.And(expression.Body, invokedExpr), expression.Parameters);
            }

        }

        
return expression;
    }
主查询是这个样子:
        var result = new DongBlogDataContext().Blogs.Where(getCondition());
因为根据SQL追踪,生成SQL类似:
SELECT [t0].[BlogID][t0].[ChannelID][t0].[BlogClassID][t0].[Title][t0].[Content][t0].[Tag][t0].[CreateDateTime]
FROM [dbo].[Blog] AS [t0]
WHERE [t0].[BlogClassID] IS NULL

这种方法是实质是合并Lamba表达式,也就是这三句:

                Expression<Func<Blog, bool>> e = blog => blog.BlogClass == null;
                var invokedExpr 
= Expression.Invoke(e, expression.Parameters.Cast<Expression>());

                expression 
= Expression.Lambda<Func<Blog, bool>>(Expression.And(expression.Body, invokedExpr), expression.Parameters);

如果每个条件合并都这么写会很麻烦,幸好已经有人给写好的辅助类:http://www.albahari.com/expressions/

using System;
using System.Linq;
using System.Linq.Expressions;
using System.Collections.Generic;
 
public static class PredicateBuilder
{
  
public static Expression<Func<T, bool>> True<T> ()  return f => true;  }
  
public static Expression<Func<T, bool>> False<T> () return f => false; }
 
  
public static Expression<Func<T, bool>> Or<T> (this Expression<Func<T, bool>> expr1,
                                                      Expression
<Func<T, bool>> expr2)
  
{
    var invokedExpr 
= Expression.Invoke (expr2, expr1.Parameters.Cast<Expression> ());
    
return Expression.Lambda<Func<T, bool>>
          (Expression.Or (expr1.Body, invokedExpr), expr1.Parameters);
  }

 
  
public static Expression<Func<T, bool>> And<T> (this Expression<Func<T, bool>> expr1,
                                                       Expression
<Func<T, bool>> expr2)
  
{
    var invokedExpr 
= Expression.Invoke (expr2, expr1.Parameters.Cast<Expression> ());
    
return Expression.Lambda<Func<T, bool>>
          (Expression.And (expr1.Body, invokedExpr), expr1.Parameters);
  }

}

这个类可以用于Expression<Func<T, bool>>类型的表达式的合并了。具体用法参看http://www.albahari.com/expressions/http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=1745163&SiteID=1

2,构造Query
同第一种查询更好的写法:

    private IQueryable<Blog> getQuery()
    
{
        IQueryable
<Blog> query = new DongBlogDataContext().Blogs;
        
if (!String.IsNullOrEmpty(Request["BlogClassID"]))
        
{
            
int blogClassID;
            
if (Int32.TryParse(Request["BlogClassID"], out blogClassID))
                query 
= query.Where<Blog>(blog => blog.BlogClass == null);
        }


        
return query.OrderByDescending(blog => blog.CreateDateTime);
    }

主查询

var result = getQuery();

生成的SQL和第一个完全相同。

园子里相关讨论还有
http://www.cnblogs.com/neuhawk/archive/2007/07/07/809585.html
http://www.cnblogs.com/blusehuang/archive/2007/07/13/816970.html
还可参考:
http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=1706161&SiteID=1