使用操作符重载,生成ORM实体类的SQL条件语句

简介:

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版开源



    本文转自深蓝医生博客园博客,原文链接:http://www.cnblogs.com/bluedoctor/archive/2012/02/27/2369256.html,如需转载请自行联系原作者



相关文章
|
9月前
|
SQL 安全 数据库
如何在Django中正确使用参数化查询或ORM来避免SQL注入漏洞?
如何在Django中正确使用参数化查询或ORM来避免SQL注入漏洞?
562 77
|
9月前
|
SQL 安全 数据库连接
除了使用Django的ORM,还能通过什么方式在Django中避免SQL注入漏洞?
除了使用Django的ORM,还能通过什么方式在Django中避免SQL注入漏洞?
230 73
|
SQL Java 数据库
建模底层逻辑问题之ORM框架建模中,执行SQL的过程中被抽象和组织是如何实现的
建模底层逻辑问题之ORM框架建模中,执行SQL的过程中被抽象和组织是如何实现的
121 2
|
SQL 缓存 Java
JAVAEE框架技术之8-myBatis ORM框架技术参数和动态SQL语句
JAVAEE框架技术之8-myBatis ORM框架技术参数和动态SQL语句
162 0
JAVAEE框架技术之8-myBatis ORM框架技术参数和动态SQL语句
|
SQL 存储 设计模式
[Python] Django ORM与执行原生SQL实现操作数据库(上)
[Python] Django ORM与执行原生SQL实现操作数据库(上)
|
SQL 设计模式 Java
用建造者模式实现一个防SQL注入的ORM框架
以构建一门课程为例,一个完整的课程由PPT课件、回放视频、课堂笔记、课后作业组成,但是这些内容的设置顺序可以随意调整,我们用建造者模式来代入理解一下。首先创建一个产品类Course。
136 0
|
SQL 数据库 数据库管理
SQLAlchemy 入门:Python 中的 SQL 工具包和 ORM
SQLAlchemy 是 Python 中一款非常流行的数据库工具包,它对底层的数据库操作提供了高层次的抽象。在本篇文章中,我们将介绍 SQLAlchemy 的两个主要组成部分:SQL 工具包 (SQL Toolkit) 和对象关系映射器 (Object-Relational Mapper, ORM) 的基本使用。
|
SQL API 数据库
[Python] Django ORM与执行原生SQL实现操作数据库(下)
[Python] Django ORM与执行原生SQL实现操作数据库(下)
|
SQL 数据库 Python
Django打印ORM执行sql语句日志
Django打印ORM执行sql语句日志
703 0
|
SQL 存储 Java
阿里JAVA手册之MySQL数据库 (建表规约、索引规约、SQL语句、ORM映射)
码出高效、码出质量。 代码的字里行间流淌的是软件生命中的血液,质量的提升是尽可能少踩坑,杜绝踩重复的坑,切实提升质量意识。另外,现代软件架构都需要协同开发完成,高效协作即降低协同成本,提升沟通效率,所谓无规矩不成方圆,无规范不能协作。
10576 0