今天,我自己的第一个ORM框架终于上线了,既感自豪,又深之很知其不完善,还有很多地方需要改进,只能日后慢慢修正,逐渐积累应用各种技术,不断完善。
我博客是使用类似PetShop框架开发,但于之不同的是采用了ORM框架,简化底层的数据访问,并实现跨数据库的访问。PetShop是提供了业务逻辑接口,并针对SQL Server和Oracle各自单独实现,但其实大部分都是那些DML操作,且不同的数据库的SQL语法大都相同,因此可利用它们的相同之处重用,即使用ORM来兼容各种数据库的访问,或是说ORM底层自动判断数据库类型再使用不同语法特性来实现,这便是ORM框架最重要的作用之一。
基于ADO.Net,各种主流数据库的访问得以支持实现,Access可使用OleDb,SQL Server使用SqlClient,Oracle使用OracleClient,而MySql使用MySql.Data开源库,且ADO框架提供了良好的接口,如要提供对其他数据库的支持只需实现ADO接口。当然,在我的ORM里为了更好的封装,我也定义了一些接口:
如上图所示,IDbExecutor接口定义数据库操作,包括数据库连接字符串ConnectionString申明,另外还包括一个Dialect数据库方言接口的属性,它必须是IDialect接口的实例,IDialect接口定义生成SQL语句方法,这样便能根据不同数据库生成不同的SQL语句。那如何兼容各种数据库不同语法特性呢?因此必须把不同数据库之间的这些差异作为接口提取出来,在实现时再根据不同的数据库选择不同的接口类实例,下面整理出几种不同数据库语法上的一些差异。
Access | SQL2000 | SQL2005 | Oracle | MySql | |
---|---|---|---|---|---|
表关联 | 两个以上表关联需要使用()括弧 例如: SELECT * FROM ((A INNER JOIN B ON A.id = B.id) INNER JOIN C ON B.id = C.id) |
正常使用 | 正常使用 | 9i后正常使用,之前版本可使用隐性连接 例如: SELECT * FROM A,B WHERE A.id = b.id |
正常使用 |
Top | 正常使用 | 正常使用 | 正常使用 | 不支持Top字句,但支持RowNum伪列 例如: SELECT * FROM A WHERE RowNum < 10 |
不支持Top子句,但支持LIMIT选项 例如: SELECT * FROM A LIMIT 10 |
分页 | 使用Top子查询实现 例如: SELECT TOP 10 * FROM A WHERE id NOT IN (SELECT TOP 10 id FROM A ORDER BY id DESC) ORDER BY id DESC |
同Access | 使用ROW_NUMBER函数分页 例如: SELECT * FROM (SELECT ROW_NUMBER() OVER(ORDER BY id DESC) AS ROWNUM,* FROM A) AS T WHERE ROWNUM BETWEEN 10 AND 20 |
使用RowNum伪列和子查询实现 例如: SELECT * FROM (SELECT *,RowNum Row_Num FROM (SELECT * FROM A ORDER BY id DESC) T) TT WHERE Row_Num BETWEEN 10 AND 20 |
使用LIMIT字句实现 例如: SELECT * FROM A ORDER BY id DESC LIMIT 10, 10 |
参数 | @Param | @Param | @Param | :Param | ?Param |
标识 | [] | [] | [] | "" | `` |
主键 | @@identity | @@identity | @@identity | Sequence.Nextval | last_insert_id() |
过程 | 不支持 | 支持 例如: exec proc |
支持 例如: exec proc |
支持 例如: exec proc() |
支持 例如: call proc() |
函数 | 不支持 | 支持 | 支持 | 支持 | 支持 |
假如我们需要使用ORM很好的兼容各种数据库,就必须尽量少用数据库的特有语法,或是说把这些功能留给ORM底层去实现,这样才能使ORM框架通用,才不至于受数据库类型的制约。但有时候我们项目难免会碰到一些复杂的业务逻辑,难免就要使用存储过程或函数等,这时就要考虑换成其他数据库是否能实现,当然这也要视项目的具体情况而定,如果不存在数据库的移植性,则就没必要了。