首页logo
  •  

jonllen

金龙,目前就职于一家软件公司,从事Java和.Net信息安全开发设计。

个人档案

jonllen
心情闪存 | 给他留言
妮称:jonllen
来自:中国. 湖南. 湘潭
简述:金龙,目前就职于一家软件公司,从事Java和.Net信息安全开发设计。
博客日历

我的ORM(一)——重复造轮子

分类:Asp.Net

ORM在我们平时项目里是必不可少的,也是最重要的系统架构之一,它提供对数据访问的底层实现,比较出名的有Java里的Hibernate、.Net里的NHibernate和Linq,这些都是很成熟的ORM框架,今天我要说的是我的ORM,这当然不能和前面说的那些ORM比,这里仅当自己造轮子学习。

使用Attribute元数据

用过Hibernate等ORM的童鞋都知道,可以使用XML文件来配置数据表和实体对象的关系,虽然说这样可以更灵活一些,但我是比较反感这些繁杂的配置的,讨厌一大堆的配置文件,所以我这里是先采用了元数据的方法,将这些配置直接嵌入在代码里,使用Attribute元数据来标识实体对象和属性。一个简单的Breast实体类如下:

[EntityFlag(TableName = "bl_breast")]
public class Breast: ModelBase
{

private User user;

public User User
{
get { return user; }
set { user = value; }
}

private Int32 breastId;

[ColumnFlag( PrimaryKey
=true)]
public Int32 BreastId
{
get { return breastId; }
set { breastId = value; }
}

private Int32 userId;

[ColumnFlag]
public Int32 UserId
{
get { return userId; }
set { userId = value; }
}

private String breast;

[ColumnFlag(ColumnName
= "breast")]
public String BreastContent
{
get { return breast; }
set { breast = value; }
}

private DateTime addDate;

[ColumnFlag]
public DateTime AddDate
{
get { return addDate; }
set { addDate = value; }
}

上面的EntityFlag和ColumnFlag都是Attribute元数据,其中的TableName和ColumnName、PrimaryKey分别为元数据属性,代表对应的表名和列名。获取的时候也很简单,使用GetCustomAttributes能返回对象的所有元数据,获取对象所有ColumnFlag标识方法如下:

public static List<ColumnFlag> GetPropertyAnnotations(Type t)
{

List
<ColumnFlag> propertyAnnotations = new List<ColumnFlag>();

PropertyInfo[] properties
= t.GetProperties();

foreach (PropertyInfo property in properties)
{

object[] attrs = property.GetCustomAttributes(true);

foreach (object attr in attrs)
{
if (attr is ColumnFlag)
{
ColumnFlag propertyAnnotation
= (ColumnFlag)attr;

if (String.IsNullOrEmpty(propertyAnnotation.ColumnName)) {
propertyAnnotation.ColumnName
= property.Name;
}

propertyAnnotation.TargetPropertyInfo
= property;

propertyAnnotations.Add(propertyAnnotation);
}
}
}

return propertyAnnotations;
}

元数据在Java里叫注解,hibernate和springframework中有大量的应用,如Controller控制层的里URL路由地址配置:

@Controller
@RequestMapping(
"/member/account.do")
public class AccountController {

@Autowired
private MemberService memberService;

@RequestMapping(params
= "action=editin")
public ModelAndView edit_in() {
HashMap
<String, Object> model = new HashMap<String, Object>();
List
<Loving> lovings = memberService.listAllLoving();
model.put(
"lovings", lovings);

List
<Department> departments = memberService.listAllDepartment();
model.put(
"departments", departments);

return new ModelAndView("/member/edit", model);
}
}

这些配置都是ORM的核心,通过获取这些信息就可为生成SQL语句做准备了,而访问数据库的主要方法就是在BaseDao类里实现的。

参数化查询

简单的拼接SQL很容易,但要避免一些SQL注入等问题,就必须要使用参数化的查询,即使遇到一些像like等的查询没办法一定要拼接字符串的时候,也要在基类里集中进行处理,一个BreastDAL数据库访问类如下:

BreastDAL数据访问类

BaseDao是一个泛型类,占位符T是约束了实体类必须由BaseBean派生,因此在基类就可预先获取实体类的元数据注解,以便生成SQL语句,另外JoinTable(表关联)、Expression(条件)、Order(排序)等作为生成SQL的元素,为的是尽量不要直接写SQL语句,而像hibernate框架中专门有HQL语言,这是一种为完全面向对象查询的有意识设计,当然一些非常复杂的SQL语句还得直接写SQL或改用存储过程才行。

不同数据库和分页实现

为了提供不同数据库的访问,特别是SQL语法和主键的一些差异,需要提供良好的配置接口,以达到不改SQL而兼容各种数据库的访问,基类需要根据不同数据库进行不同处理,最大的难度可能是服务器分页处理上了,因为Access、SQL2000、SQL2005、Oracle、MYSQL分页几乎各不一样,这就必须要解藕一一实现,由于我目前只实现了Access的分页,且一些效率问题还没有经过测试,所以这里就不深入撰述了,不过以后的SQL2005、Oracle、MYSQL分页实现稍微都会简单些,因为都有内置分页函数支持。

代码生成

凡是企业级的开发,都会讲究效率问题,特别是针对自己的框架特点,做一个简单的代码生成工具自动生成一些Bean和Dao还是很有必要的,也就是根据数据库表结构生成对应的CS文件。Access数据库有点麻烦,先需要进入数据库,勾选工具>选项>视图>显示隐藏对象,然后再工具>安全>用户与组权限>选中对象名称MSysObjects,在权限里至少勾选读取数据和读取设计选项,这样才能读取Access数据库里的所有表,至于列嘛可以不必直接再去查询,因为查询表的数据里也会包含所有列信息,并且可以获取对应的.Net数据类型,所以生成代码的时候就没必要映射据类型了,简单处理就好。

标签:Asp.Net ORM框架
  • posted@ 2010-07-01 23:36
  • update@
  • 阅读(10079)
  • 评论(0)
评论
暂无任何评论。
发表评论
*必填
回复通知我
*必填

博文推荐