继LINQ动态组合查询PredicateExtensions讲解

简介:

LINQ动态组合查询中我留下了一个问题就是PredicateExtensions。在这里很简单不需要什么多的基础只要比会And、Or逻辑运算数学知识就够了。

先贴上代码好分析:代码

 
  1. public static class PredicateExtensions  
  2.     {  
  3.         public static Expression<Func<T, bool>> True<T>() { return f => true; }  
  4.  
  5.         public static Expression<Func<T, bool>> False<T>() { return f => false; }  
  6.  
  7.         public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> expression1,   
  8.            Expression<Func<T, bool>> expression2)  
  9.         {  
  10.             var invokedExpression = Expression.Invoke(expression2, expression1.Parameters  
  11.                     .Cast<Expression>());  
  12.  
  13.             return Expression.Lambda<Func<T, bool>>(Expression.Or(expression1.Body, invokedExpression),  
  14.             expression1.Parameters);  
  15.         }  
  16.  
  17.         public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> expression1,   
  18.               Expression<Func<T, bool>> expression2)  
  19.         {  
  20.             var invokedExpression = Expression.Invoke(expression2, expression1.Parameters  
  21.                  .Cast<Expression>());  
  22.  
  23.             return Expression.Lambda<Func<T, bool>>(Expression.And(expression1.Body,   
  24.                    invokedExpression), expression1.Parameters);  
  25.         }  
  26.     }  

   在其中只有四个方法,True、False、Or、And,一看大家就知道这里是对逻辑运算操作。其中True、False是对表达式进行初始化,在我没有看见这个类之前我用的是null,用null这要在没有And,Or逻辑操作时进行Null判断,如果null则返回后一个表达式。而在这里有了true,fakse这相当于初始化了一个表达式,就不用再那么麻烦了。

     True、False的初始化有一个规则就是不能影响我们的正常表达式.在我们刚学语言的时候就有:逻辑与一假为假,逻辑或一真为真,那这句就可以运用于我们的这两表达式的初始化了。当我们在True、False初始化表达式和后便连接的表达式逻辑运算为And时候,我们就该用True,这么这个逻辑条件的真假取决于我们的后面表达式(逻辑与一假为假,一真那么还不确定),是不是没有影响我们的正常表达式?同理逻辑运算为Or时候,就该用False(逻辑或一真为真,一假也不确定,就取决于另一个表达式)。是不是很简单,还是那句话,我这种鼠辈估计很难想到,是应试教育禁锢了我们的思维啊!

      And、Or这是表达式逻辑运算连接,那主体为取出左边表达式body Invoke了再与右边表达式连接返回。

     为了验证我的结论,我们做几个小测试(这里为了方便改为了控制台程序):

测试1:True and连接;代码

 
 
  1. public static void Test1()  
  2.         {  
  3.             DbDataContext db = new DbDataContext();  
  4.             Expression<Func<TemplateDocument, bool>> expressleft =   
  5.                                 PredicateExtensions.True<TemplateDocument>();  
  6.             expressleft = expressleft.And(t => t.CategoriesID > 3);  
  7.  
  8.             Expression<Func<TemplateDocument, bool>> expressright =   
  9.                                 PredicateExtensions.True<TemplateDocument>();  
  10.             expressright = expressright.And(t => t.CategoriesID < 5);  
  11.  
  12.           expressleft=  expressleft.Or(expressright);  
  13.           var sql = db.GetCommand(db.TemplateDocument.Where(expressleft).Select(t => new {   
  14.                            t.TemplateID, t.TemplateName, t.CategoriesID })).CommandText;  
  15.             Console.WriteLine(sql);  
  16.  
  17.         }  

输出sql:

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

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

WHERE ([t0].[CategoriesID] > @p0OR ([t0].[CategoriesID] < @p1

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

测试2 代码

 
  1. public static void Test2()  
  2.         {  
  3.             DbDataContext db = new DbDataContext();  
  4.             Expression<Func<TemplateDocument, bool>> expressleft =   
  5.                              PredicateExtensions.False<TemplateDocument>();//上例True该为False 
  6.             expressleft = expressleft.Or(t => t.CategoriesID > 3);//上例And该为Or 
  7.  
  8.             Expression<Func<TemplateDocument, bool>> expressright =   
  9.                               PredicateExtensions.False<TemplateDocument>();  
  10.                           //上例True该为False 
  11.             expressright = expressright.Or(t => t.CategoriesID < 5);  
  12.                           //上例And该为Or 
  13.             expressleft = expressleft.Or(expressright);  
  14.             var sql = db.GetCommand(db.TemplateDocument.Where(expressleft).Select(t => new {   
  15.                          t.TemplateID, t.TemplateName, t.CategoriesID })).CommandText;  
  16.             Console.WriteLine(sql);  
  17.  
  18.         }  
 

输出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: 代码

 
  1. public static void Test3()  
  2.         {  
  3.             DbDataContext db = new DbDataContext();  
  4.             Expression<Func<TemplateDocument, bool>> expressleft =  
  5.                                  PredicateExtensions.True<TemplateDocument>();  
  6.             expressleft = expressleft.Or(t => t.CategoriesID > 3);  
  7.  
  8.             Expression<Func<TemplateDocument, bool>> expressright =   
  9.                 PredicateExtensions.False<TemplateDocument>();  
  10.                                     expressright = expressright.Or(t => t.CategoriesID < 5);  
  11.  
  12.             expressleft = expressleft.And(expressright);  
  13.             var sql = db.GetCommand(db.TemplateDocument.Where(expressleft).Select(t => new {   
  14.                                     t.TemplateID, t.TemplateName, t.CategoriesID })).CommandText;  
  15.             Console.WriteLine(sql);  
  16.  
  17.         } 

输出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情况一样,我就不去推导了,偷个懒。 
 

以上全是个人意见,如果有什么不对了请指导,更正。





 本文转自 破狼 51CTO博客,原文链接:http://blog.51cto.com/whitewolfblog/834695,如需转载请自行联系原作者


相关文章
|
开发框架 搜索推荐 .NET
推荐一个C#全文搜索支持Linq表达式的开源项目
一个IQueryable与IEnumerable扩展方法库
146 0
推荐一个C#全文搜索支持Linq表达式的开源项目
|
SQL 开发框架 .NET
【菜鸟看框架】——Linq实现动态模糊查询
【菜鸟看框架】——Linq实现动态模糊查询
355 0
【菜鸟看框架】——Linq实现动态模糊查询
|
.NET 开发框架 SQL
Linq动态条件
很多情况下,我们开发程序,需要动态拼接SQL查询语句; 比如  select top 1 * from User where age= 18  and  name = 'renruiquan' 其中红色的代码,是我们需要根据查询条件是否为空,来判,要不要加在查询的SQL里; 换成Linq里就不能这么直接的去拼接了,好在国外的大神有给我们解决方案。
1476 0
|
SQL 存储 .NET
艾伟_转载:打造优雅的Linq To SQL动态查询
  首先我们来看看日常比较典型的一种查询Form   这个场景很简单:就是根据客户名、订单日期、负责人来作筛选条件,然后找出符合要求的订单。   在那遥远的时代,可能避免不了要写这样的简单接口: public interface IOrderService{  IList Search(string customer, DateTime dateFrom, DateTime dateTo, int employeeID);}   具体爱怎么实现就怎么实现啦,存储过程,ORM框架。
1173 0
|
机器学习/深度学习 .NET