代码改变世界

尝试写一个简单的ORM

2008-09-20 14:40  JimLiu  阅读(683)  评论(3编辑  收藏  举报
由于本学期有门数据库课程设计,所以可能需要做些东西。一直用NHibernate, Linq to Sql这样的ORM,很喜欢基于ORM的数据访问层设计。可是我要是用别人的ORM框架数据库老师非劈了我不可,所以只能自己尝试着写一个咯。

思路上基本上还算挺明确了,我不需要强大的性能和功能,只需要能完成小得不能再小的应用的数据访问就可以,但是既然要做就尽量做得完整点吧,所以我是这么设计的:

数据提供还是通过Provider来实现,这没什么说的。

映射的配置,不是很喜欢XML的配置方式,总觉得和类的定义分开了不是那么舒服,所以当然是.NET 大名鼎鼎的Attribute啦!

CRUD基本上来说还是比较容易的,一个是因为我不用怎么考虑性能问题,我可以大摇大摆地用反射,另一方面因为我不考虑在关联的时候进行自动级联,而是由BLL来完成,听起来可能觉得很不爽,不过这的确是因为我发现要实现级联在我自己的技术范畴里估计有点吃不消- -|,所以我只能偷这个懒了。

查询条件,这个是个大头,想了很久我没想到一个比较爽的方案,最终结合了我所看过的一些ORM实现,我弄成了这么个样子
Query query = new Query("{0}||{1}",
    Expression.Eq
<Product>("Name", name),
    Expression.Gt
<Product>("ID", minID));
query.RowLimit 
= 20;
query.Order.Add(OrderBy.Asc
<Product>("ID"));

当执行某些操作的时候(当然是由我的接口来定)就构造个Query传进去,Query是个抽象类,定义了个Translate()方法,在执行查询的时候就翻译成SQL。

关联,还是关联,没有了关联,ORM也就不能称其为ORM,关系数据库也就无法称其为关系数据库。我希望达到的效果大概要是这个样子
// 像这样
Product product = xxx.Get<Product>(query);
Console.WriteLine(product.User.Name);
// 还有
User user = xxx.Get<User>(query);
foreach (Product p in user.Products){
    Console.WriteLine(p.Name);
}

就是说虽然数据库里存的是Product.UserID这个外键,但是并不在实体类里暴露,而是直接暴露一个User对象;User实体类中也相应暴露一个many段Products。这样来说思维很清晰了。但是我实现起来却卡壳了,因为虽然Product没有UserID这个属性了,但是在查询 Product.User的时候这个属性是需要的啊!这里我就很郁闷,没有好的办法。刚才我突然想到一个办法就是在生成Product的时候就把数据库里 UserID那项读出来,然后new一个User,把User.ID赋值为读出来那个UserID,以后再查询Product.User的时候就可以找到这个隐藏起来的Product.UserID,这样做在生成对象的时候实现也许会比较麻烦,不过我觉得思路还是清晰点了,而且即可以通过类似 LoadEntitySet这样的方法来后期获得,也可以直接join进来在生成Product的时候就把User对象创建好——根据业务的需要来决定。

继承——在这个小ORM里我不打算实现继承了,很大一部分原因是我本身对ORM的继承理解就不好。

其他的有个问题就是,我想从一开始就设计成让它支持多种数据库,但是不同的数据库SQL语法是有区别的,举个例子sql server中有top xx限制记录条数,mysql中就用limit;不同的数据库对Parameter的命名也不一样,这就比较头疼了。一个方法就是完全独立的实现,我想我一个人短时间内写那么多Provider到头非疯了不可。看了NHibernate的Dialect,巨复杂,不怎么看的懂。后来我想了一种基本上不顾效率的方法——SQL模板,不同的Provider实现不同的模板,每个模板分为若干部分,由于我不用做得太复杂,所以这样简单的查询类似于
public override string SelectTemplate {
    
get { return @"SELECT {limit} {columns} FROM {tablename} {query};"; }
}

这是一个Sql Server的Select语句的模板,实际上已经足够我满足大多数查询了,因为我只支持单表操作。这样只要不是很BT的查询,都基本上可以复用很多一部分代码。

总的来说我这个所谓的ORM实在是很欠扁,不过我做它的目的就是为了完成一个简单应用的数据访问,不说是ORM说成是一个DataAccessLayer也成,因为我从来没做过这样的东西,所以很多地方实在很弱。不过反正这个东西这辈子估计也就我一个人会用它,就不管这么多啦!以后身处团队再考虑更多框架技术吧。

编码继续中……