在LINQ动态组合查询中我留下了一个问题就是PredicateExtensions。在这里很简单不需要什么多的基础只要比会And、Or逻辑运算数学知识就够了。
先贴上代码好分析:
代码
public
static
class
PredicateExtensions
{
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
>>
expression1,
Expression
<
Func
<
T,
bool
>>
expression2)
{
var invokedExpression
=
Expression.Invoke(expression2, expression1.Parameters
.Cast
<
Expression
>
());
return
Expression.Lambda
<
Func
<
T,
bool
>>
(Expression.Or(expression1.Body, invokedExpression),
expression1.Parameters);
}
public
static
Expression
<
Func
<
T,
bool
>>
And
<
T
>
(
this
Expression
<
Func
<
T,
bool
>>
expression1,
Expression
<
Func
<
T,
bool
>>
expression2)
{
var invokedExpression
=
Expression.Invoke(expression2, expression1.Parameters
.Cast
<
Expression
>
());
return
Expression.Lambda
<
Func
<
T,
bool
>>
(Expression.And(expression1.Body,
invokedExpression), expression1.Parameters);
}
}
在其中只有四个方法,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连接;
代码
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情况一样,我就不去推导了,偷个懒。
以上全是个人意见,如果有什么不对了请指导,更正。