应当重视选择ORM

以专业开发人员为伍 2008-02-27 12:59:14
加精
面向对象有它的本质要求。如果你的编程仅仅是“基于对象”而不是“面向对象”的,虽然你也能收到一些“代码封装成类型”的好处,但是你其实很难用到真正深入的面向对象软件工程设计技术。

面向对象ORM非常重要,堪称面向对象软件工程技术的核心。但是,有很多ORM只是“基于对象”的,不是“面向对象”的。面向对象的ORM应该与面向对象的软件工程技术一样,首要问题是:解决基于对象的结构化技术(如今所有顽固坚持结构化技术的人都使用OOPL语言来说明自己的理论,因此OOPL不等代表OO的水平)与基于多态的面向对象技术的“阻抗不匹配”现象。

套用面向对象技术的本质特种,面向对象ORM应该有以下本质特征(下面是用了熟悉的c#的术语):

1. 自动维护类型定义。我们把一个对象“丢给”面向对象ORM,它就应该自动分析对象的Field、Property。如果在使用一段时间之后我们的对象类型定义改变了,原来的数据应该仍然能够回复为新的类型的对象,只不过有些新增字段成为默认值。例如:

User u=null;
//todo: 产生u实例
using(var db=Domain(数据库连接))
{
db.Save(u);
db.Commit();
}
db事先并不知道“User”这个类型,它应该“临时”反射User类型并记录下来。那些要求我们依据关系数据库的数据字典来写class代码的想法可谓“居心叵测”。

2. 标识唯一性。至少在同一个进程中(也就是在同一个ORM环境中)两个不同的查询,如果逻辑上应该有相同的对象返回,那么ORM就应该体现这个规则。例如有一个过程是“保存工单记录”,工单中有字段记录负责评估工单的产品经理,另外有一个过程是“查询某个项目组的产品经理”。看上去这两个过程没有紧密的逻辑联系,但是他们有数据联系。如果一个地方建立个一个产品经理对象并调用了第一个方法,另一个地方随后调用了第二个方法,那么对于同一个产品经理,第二个方法不应重新建立新的内存对象,而应该返回第一个方法所使用的那个对象(除非调用第二个方法时第一个方法使用的那个对象已经被GC释放了)。

显然,你的ORM应该有自己的缓存机制来维护对各个对象的弱引用。缓存并不是仅用来提高查询速度的,还有逻辑意义上的用处。

3. 继承性。如果上述例子中的变量u被实例化为一个从User类继承的“系统管理员”类,数据库当然应该可以保存,并且在随后“查询系统管理员”操作中可以正确返回系统管理员的全部字段。显然,子类和父类在数据库中肯定要分开成不同的类型(或者叫做“表”)。

例如假设Domain数据库类型的Query<T>返回所有T类型对象的一个QueryProvider(Linq定义的):
User u=null;
u=new 系统管理员(){姓名="大宝"}; //已经设置(例如使用一个Attribute在class中声明)“姓名”在数据库中是唯一的。
using(var db=Domain(数据库连接))
{
db.Save(u);
db.Commit();
var result=(from u in db.Query<系统管理员> where u.姓名=="大宝" select u).FirstOrDefault();
//todo: result.Print();
}

4. 多态性。

User u=null;
u=new 系统管理员(){姓名="大宝"}; //已经设置(例如使用一个Attribute在class中声明)“姓名”在数据库中是唯一的。
using(var db=Domain(数据库连接))
{
db.Save(u);
db.Commit();
var result=(from u in db.Query<User> where u.姓名=="大宝" select u).FirstOrDefault();
//todo: result.Print();
}
注意result的定义类型是User而不是“系统管理员”。多态让我们写出“引擎式”的代码,这个引擎拖动的车子是虚构的、通用的。ORM应该支持OO的这个本质要求。

5. 网状关联。ORM应该隐藏面向对象数据库与关系数据库在处理关联方面的差别。

假设User中有一个“配偶”字段,并且有一个“情人”集合,查询“系统管理员的配偶和情人”方法可能这样写:

User u=null;
u=new 系统管理员(){姓名="大宝"}; //已经设置(例如使用一个Attribute在class中声明)“姓名”在数据库中是唯一的。
//todo: u.配偶=......
using(var db=Domain(数据库连接))
{
db.Save(u);
db.Commit()
var result1=from u in db.Query<系统管理员> select u.配偶;
//todo: result1.ForEach(p=>{p.Print();});
var result2=(from u in db.Query<系统管理员> select u).SelectMany(u=>u.情人);
//todo: result2.ForEach(q=>{q.Print();});
}
如果你使用面向对象数据库,那么从User到它的配偶之间以及每一位情人之间的存储关联是“一步到位”的,而不是像关系数据库那样需要使用inner join。因此,面向对象昂数据库(理论上)应该比关系数据库速度快至少10倍。

不应该强迫对象类型之间关系模仿关系数据库的“外键”来建立,应该使用上面的自然、OOPL原始的形态。这样,如果你的ORM的底层是关系数据库,例如是SQL Server,那么你的QueryProvider(Linq)实现就不得不将关系翻译为关联操作。

6. 延迟加载。显然,当我们查询一堆User出来之后,它的“七姑八姨”等关系对象不需要加载到内存里(否则这个加载操作就太可怕了),但是当我们访问关联对象时应该自动从数据库中加载到内存。对于引用单个对象和引用集合对象都是应该这样的。

7. 级联更新。如果我们实例化一个User类型对象,并且给它的“配偶”赋值,那么在保存这个User类型对象的时候就应该自动保存(新增或者更新都叫是保存操作)它的配偶,而不需要我们在程序中去写保存配偶的代码。如果我们查询出一个User,他有很多情人,我们用程序向他的“情人集合”里插入一个情人或者删除一个情人,然后保存他,那么ORM应该自动也去保存这个情人或者删除它与这个情人的数据库内连接,但是不需要重复保存那些没有动过的情人对象。

<完>
...全文
5625 100 打赏 收藏 转发到动态 举报
写回复
用AI写文章
100 条回复
切换为时间正序
请发表友善的回复…
发表回复
  • 打赏
  • 举报
回复
upup
testtestett 2011-03-31
  • 打赏
  • 举报
回复
有意思
fesly 2011-03-28
  • 打赏
  • 举报
回复
yesliu 2011-02-14
  • 打赏
  • 举报
回复
对我的启发非常大!谢谢各位的言论!
feiyvefanli 2011-02-10
  • 打赏
  • 举报
回复
100楼 掘坟 顶一下


楼主写得不错


别要求这世界要终极通杀的东西了
否则出一框架 秒杀全部 程序员全体失业
twfx7758 2008-10-06
  • 打赏
  • 举报
回复
mark
cooolchen 2008-10-02
  • 打赏
  • 举报
回复
好帖不能错过!
mingbing 2008-09-04
  • 打赏
  • 举报
回复
云里雾里的感觉!
lizhongkun 2008-08-31
  • 打赏
  • 举报
回复
gz
ctrlenterogn 2008-08-30
  • 打赏
  • 举报
回复
实现起来有困难呀
flyingfz 2008-08-29
  • 打赏
  • 举报
回复
呵呵,感觉就是 设计模式 .
flyingfz 2008-08-29
  • 打赏
  • 举报
回复
mark
llxchen 2008-08-28
  • 打赏
  • 举报
回复
有种说不出的感觉,现在的工作经验和环境让俺太少能够关注到这些深层次的东西
wolf_life 2008-08-28
  • 打赏
  • 举报
回复
啥也不说了。。顶
cqg1220 2008-08-27
  • 打赏
  • 举报
回复
搞得压力大了,不过机柜还是要支持一下楼主!
cg2003 2008-08-27
  • 打赏
  • 举报
回复
UP
guboyin 2008-08-27
  • 打赏
  • 举报
回复
搞得压力大了
freeflying1222 2008-08-26
  • 打赏
  • 举报
回复
[Quote=引用 82 楼 sp1234 的回复:]
引用 66 楼 caicai_45 的回复:
回版主:

确实不错,是我火气大了点。 但是觉得不是针对你的。 sp1234的有些观点,真的太过学院化,说实话,有些理论,就是书本上的东西,
如果都按照他说的来,项目小还行,大的都按照他说的搞,真会死的。。。。 之前的ViewState越大越好,哎不知道说啥好了。
这次又来个ORM模型。 而且每次基本都是版主给加精了,讨论可以,要是一些新手真按照他说的来,确实会遇到问题的…
[/Quote]
我是新手,但肯定不按照他说的来,因为看都看不懂,呵呵。
但还是很喜欢有更多这样的文章。csdn不应该只是“菜鸟的天堂”!
就算菜鸟,也需要方向和视野。
所以向SP1234致敬。

当然也应该感谢所有参与谈论的高手们,虽然有激烈的争执。
  • 打赏
  • 举报
回复
我只是回复对切实可行的方案 --> 我通常只是拿出对自己切实可行研究过并且实现和经过反复测试的方案回复

而不是提出一个概念作为回复。
加载更多回复(80)

13,190

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 分析与设计
社区管理员
  • 分析与设计社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧