Expression表达式树的And、Or逻辑运算

PredicateBuilder类(linq多条件组合查询)

复制代码
public static class PredicateBuilder
    {
 
        /// <summary>
        /// 机关函数应用True时:单个AND有效,多个AND有效;单个OR无效,多个OR无效;混用时写在AND后的OR有效  
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public static Expression<Func<T, bool>> True<T>() { return f => true; }
 
        /// <summary>
        /// 机关函数应用False时:单个AND无效,多个AND无效;单个OR有效,多个OR有效;混用时写在OR后面的AND有效  
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        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);
        } 
    }
复制代码
  

     在其中只有四个方法,True、False、Or、And,一看大家就知道这里是对逻辑运算操作。其中True、False是对表达式进行初始化。

     True、False的初始化有一个规则就是不能影响我们的正常表达式.在我们刚学语言的时候就有:逻辑与一假为假,逻辑或一真为真,那这句就可以运用于我们的这两表达式的初始化了。当我们在True、False初始化表达式和后便连接的表达式逻辑运算为And时候,我们就该用True,这么这个逻辑条件的真假取决于我们的后面表达式(逻辑与一假为假,一真那么还不确定),是不是没有影响我们的正常表达式?同理逻辑运算为Or时候,就该用False(逻辑或一真为真,一假也不确定,就取决于另一个表达式)。


      And、Or这是表达式逻辑运算连接,那主体为取出左边表达式body Invoke了再与右边表达式连接返回。例如下面的片段代码:

 
复制代码
    /// <summary>
    /// 多条件查询
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    protected void btnSearch_Click(object sender, EventArgs e)
    {
        using(LinqDBDataContext db = new LinqDBDataContext())
        {
            var list = db.StuInfo;
            var where = PredicateBuilder.True<StuInfo>();
            if(this.txtName.Text.Trim().Length!=0)
            {
                where = where.And(p => p.StuName.Contains(this.txtName.Text.Trim()));
            }
            if(this.txtAge.Text.Trim().Length!=0)
            {
                where = where.And(p => p.StuAge == Convert.ToInt32(this.txtAge.Text.Trim()));
            }
            var result = list.Where(where).ToList();
            this.repStuInfo.DataSource = result;
            this.repStuInfo.DataBind();
        }
    }
复制代码

上面代码中,txtName是姓名文本框,txtAge是年龄文本框,因为要进行and条件查询所以一开始使用PredicateBuilder.True<StuInfo>()来创建初始为true的where条件,

如果进行or多条件查询,就应该使用PredicateBuilder.False<StuInfo>()来创建初始为false的where条件。为了验证我的结论,做以下测试:

 

测试1:True and连接;代码

复制代码
     public static void Test1()  
        {  
            DbDataContext db = new DbDataContext();  
            Expression<Func<TemplateDocument, bool>> expressleft =  PredicateExtensions.True<TemplateDocument>();          
            expressleft = expressleft.And(t => t.CategoriesID > 3);  
 
            Expression<Func<TemplateDocument, bool>> expressright =  PredicateExtensions.True<TemplateDocument>();  
            expressright = expressright.And(t => t.CategoriesID < 5);  
 
          expressleft=  expressleft.Or(expressright);  
          var sql = db.GetCommand(db.TemplateDocument.Where(expressleft).Select(t => new { t.TemplateID, t.TemplateName, t.CategoriesID })).CommandText;  
          Console.WriteLine(sql); 
        }  
复制代码

输出sql:

SELECT [t0].[TemplateID], [t0].[TemplateName], [t0].[CategoriesID] 

FROM [dbo].[TemplateDocument] AS [t0] 

WHERE ([t0].[CategoriesID] > @p0) OR ([t0].[CategoriesID] < @p1

不知你发现没有Linq表达式已经把True条件智能的去掉了,(True&&XX1)||(True&&XX2) = XX1||XX2。按照上面的说法,那我们把第一个条件改为False 的Or连接也应该一样,测试一下:

测试2 代码


复制代码
  public static void Test2()  
        {  
            DbDataContext db = new DbDataContext();  
            Expression<Func<TemplateDocument, bool>> expressleft =   PredicateExtensions.False<TemplateDocument>();//上例True该为False 
            expressleft = expressleft.Or(t => t.CategoriesID > 3);  //上例And该为Or 
 
            Expression<Func<TemplateDocument, bool>> expressright =   PredicateExtensions.False<TemplateDocument>(); //上例True该为False 
            expressright = expressright.Or(t => t.CategoriesID < 5);  //上例And该为Or 

expressleft = expressleft.Or(expressright); var sql = db.GetCommand(db.TemplateDocument.Where(expressleft).Select(t => new { t.TemplateID, t.TemplateName, t.CategoriesID })).CommandText; Console.WriteLine(sql); }
复制代码

输出sql

SELECT [t0].[TemplateID], [t0].[TemplateName], [t0].[CategoriesID] 

FROM [dbo].[TemplateDocument] AS [t0]

WHERE ([t0].[CategoriesID] > @p0) OR ([t0].[CategoriesID] < @p1)

和上例输出了sql完全一样,,(False||XX1)||(False||XX2) = XX1||XX2。那我们改变用法将True或Or连接呢?

测试3: 代码

复制代码
  public static void Test3()  
        {  
            DbDataContext db = new DbDataContext();  
            Expression<Func<TemplateDocument, bool>> expressleft =  PredicateExtensions.True<TemplateDocument>();  
            expressleft = expressleft.Or(t => t.CategoriesID > 3);  
 
            Expression<Func<TemplateDocument, bool>> expressright =  PredicateExtensions.False<TemplateDocument>();  
            expressright = expressright.Or(t => t.CategoriesID < 5);  
 
            expressleft = expressleft.And(expressright);  
            var sql = db.GetCommand(db.TemplateDocument.Where(expressleft).Select(t => new { t.TemplateID, t.TemplateName, t.CategoriesID })).CommandText;  
            Console.WriteLine(sql);  
        } 
复制代码

 

输出sql:

SELECT [t0].[TemplateID], [t0].[TemplateName], [t0].[CategoriesID] 
FROM [dbo].[TemplateDocument] AS [t0] 
WHERE [t0].[CategoriesID] < @p0 

只有一个表达式了,当然了啊,你第一个表达式是(True||XX1)&&(False||XX2) = True&&XX2=XX2.做了这个测试,微软在代码中能够这么智能判断。索性把条件完全弄掉,我们把中间的And改为Or:(True||XX1)||(False||XX2) = True||XX2=True。这个就自己测试了你将看不到where条件了。 肖坤Linq动态查询与模糊查询(带源码示例)中给出了一个结果总结.

  1:构造函数使用True时:单个AND有效,多个AND有效;单个OR无效,多个OR无效;混合时写在AND后的OR有效 
  2:构造函数使用False时:单个AND无效,多个AND无效;单个OR有效,多个OR有效;混合时写在OR后面的AND有效

我们来验证验证:

1构造函数使用True时:

(1):单个AND有效,多个AND有效,当然了True&&XX=XX

(2):单个OR无效,多个OR无效:True || XX=True所以无效。

(3):混合时写在AND后的OR有效:(True&&XX)||XX1=XX||XX1有效,(True||XX)&&XX1=True&&XX1=XX1,肖博前辈说的无效(相对于我们需要的表达式无效,其实还是有效) (True||XX)||XX1=True||XX1=True(这里你不会看见where条件)。

2:构造函数使用False时:

   和True情况一样,我就不去推导了,偷个懒。 
 

 

posted @   燕过留痕  阅读(664)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)
点击右上角即可分享
微信分享提示