ORM框架的一个不可或缺的功能就是根据实体类,生成操作数据库的SQL语句,这其中,最难处理的就是那些复杂的SQL条件比较语句。比如,有下面这样一个SQL语句:
SELECT
[
id
],
[
BankCode
],
[
CityCode
],
[
FundCode
],
[
FundName
],
[
FundReviews
],
[
EndDagte
],
[
addDate
]
FROM
[
FundReviews
]
WHERE (
(
[
CityCode
]
=
@CP1
OR
[
BankCode
]
=
@CP2)
AND (
[
FundCode
]
=
@CP3
OR
[
BankCode
]
=
@CP4)
)
这个复杂的查询条件由两个OR子条件最后组合成一个AND 条件的,因此它有3组条件:
1:[CityCode]=@CP1 OR [BankCode]=@CP2;
2:[FundCode]=@CP3 OR [BankCode]=@CP4;
3:1 AND 2 ;
而条件1其实就是 Condition1 OR Condition2,这又是一个条件组合。
我们发现,尽管SQL的条件语句可能很复杂,但这些条件却是由一些子条件组合成的,或者说由一组条件组合成一个新的条件,大家想想,这是不是典型的“组合模式”阿?
在PDF.NET框架的ORM组件中,有一个专门处理条件的对象OQLCompare ,它就是根据“组合模式”设计的,我们来看看怎么由它来构造这个查询条件:
1,采用AND,OR重载:
FundReviews p =
new FundReviews();
//
实例化一个实体类
OQL q =
new OQL(p);
//
实例化一个OQL对象
Console.WriteLine(
"
OQLCompare 复杂比较条件表达式测试---------
");
OQLCompare cmp =
new OQLCompare(p);
OQLCompare cmpResult = (cmp.Comparer(p.CityCode, OQLCompare.CompareType.Equal,
"
021
")
| cmp.Comparer(p.BankCode, OQLCompare.CompareType.Equal,
"
008
"))
& (cmp.Comparer(p.FundCode, OQLCompare.CompareType.Equal,
"
KF008
")
| cmp.Comparer(p.BankCode, OQLCompare.CompareType.Equal,
"
008
"));
q.Select().Where(cmpResult);
Console.WriteLine(
"
SQL=
" + q.ToString());
在OQL中,采用了类似SQL的语法,也是
Select(
[
属性列表
]).
Where(
[
条件表达式
]).OrderBy(
[
排序字段
]).GroupBy(
[
分组字段
])
其中[条件表达式]就可以使用OQLCompare对象来构造。由于OQLCompare对象Comparer函数返回的仍然是一个OQLCompare对象,所以可以利用这个特点,采用组合模式,构造出非常复杂的SQL条件语句。
我们看到OQL采用了类似函数式的语法风格,但在[条件表达式]的构造过程中,还是显得很冗长,我们可以继续对OQLCompare对象进行重构:
///
<summary>
///
设置等于某个实体属性的比较条件
///
</summary>
///
<param name="compare">
当前实体比较对象
</param>
///
<param name="Value">
要比较的值
</param>
///
<returns>
构造的实体比较对象
</returns>
public
static OQLCompare
operator ==(OQLCompare compare,
object Value)
{
return BuildOperator(compare, Value,
"
=
");
}
///
<summary>
///
设置不等于某个实体属性的比较条件
///
</summary>
///
<param name="compare">
当前实体比较对象
</param>
///
<param name="Value">
要比较的值
</param>
///
<returns>
构造的实体比较对象
</returns>
public
static OQLCompare
operator !=(OQLCompare compare,
object Value)
{
return BuildOperator(compare, Value,
"
<>
");
}
///
<summary>
///
根据实体对象的属性,获取新的条件比较对象
///
</summary>
///
<param name="field"></param>
///
<returns></returns>
public OQLCompare Property(
object field)
{
OQLCompare cmp =
new OQLCompare();
cmp.CompareString =
this.currPropName ;
return cmp;
}
private
static OQLCompare BuildOperator(OQLCompare compare,
object Value,
string operatorString)
{
string paraName = compare.GetNewParameterName();
compare.CompareString += operatorString + paraName;
compare.compareValueList.Add(paraName.Substring(
1), Value);
return compare;
}
我们可以采用类似的方式,继续实现 >=,>,<=,< 等SQL条件比较符号的重载,这里就不一一举例了,我们来看新的使用方式:
2,采用SQL比较符号的重载:
//
对象 p 为实体类
OQLCompare cmp2 =
new OQLCompare(p);
OQLCompare cmpResult2 =
( cmp2.Property(p.CityCode) ==
"
021
" | cmp2.Property(p.BankCode) ==
"
008
")
&
( cmp2.Property(p.FundCode) ==
"
KF008
"| cmp2.Property(p.BankCode) ==
"
008
");
q.ReSet();
//
重新初始化OQL
q.Select().Where(cmpResult2);
Console.WriteLine(
"
操作符重载 SQL=
" + q.ToString());
现在这个SQL条件的构造过程是不是清晰多了?这就是操作符重载的魅力:)
3,使用Equal方法,简化相等比较
直接看下面的代码,功能跟上面的例子一样:
//
对象 p 为实体类
OQLCompare cmp2 =
new OQLCompare(p);
OQLCompare cmpResult2 =
( cmp2.Equal(p.CityCode,
"
021
") | cmp2.Equal(p.BankCode,
"
008
") )
&
( cmp2.Equal(p.FundCode,
"
KF008
") | cmp2.Equal(p.BankCode,
"
008
") );
q.ReSet();
//
重新初始化OQL
q.Select().Where(cmpResult2);
Console.WriteLine(
"
操作符重载 SQL=
" + q.ToString());
从性能上来说,这种方式效率稍高,因为它是函数式的处理方式,更直接。
-------------------------------------------------------------------------
注:本文介绍的这个OQL特性仅在PDF.NET Ver 4.3版本受支持,但之前的版本参照本文说的方法加以改进,也可以使用。有关PDF.NET的版本信息,请看官网介绍:
http://www.pwmis.com/sqlmap
有关PDF.NET的开源信息,请参看我的博客文章:
节前送礼:PDF.NET(PWMIS数据开发框架)V3.0版开源