O/R Mapping 基本概念
(本文引自:http://www.cnblogs.com/idior/archive/2005/07/04/186086.html)
近日 有关o/r m的讨论突然多了起来. 在这里觉得有必要澄清一些概念, 免的大家讨论来讨论去, 才发现最根本的理解有问题.本文并不保证所有观点正确, 只是个人在某一特定时期的理解.
1. 何谓Entity?
实体(类似于j2ee中的Entity Bean)通常指一个承载数据的对象, 但是注意它也是可以有行为的! 只不过它的行为一般只操作自身的数据. 比如下面这个例子:
{
string firstName;
string lastName;
public void GetName()
{
return lastName+firstName;
}
}
GetName就是它的一个行为.
2 何谓Domain Object?
对象最重要的特性在于它拥有行为. 仅仅拥有数据,你可以称它为对象, 但是它却失去它最重要的灵魂.
{
string firstName;
string lastName;
Role role;
int baseWage;
public void GetSalary()
{
return baseWage*role.GetFactory();
}
}
这样需要和别的对象(不是Value Object)打交道的对象,我就不再称其为实体. 领域模型就是指由这些具有业务逻辑的对象构成的模型.
3. E/R M or O/R M?!!
仔细想想我们为什么需要o/r m,无非是想利用oo的多态来处理复杂的业务逻辑, 而不是靠一堆的if else.
而现在在很多人的手上o/r m全变成了e/r m.他们不考虑对象的行为, 而全关注于如何保存数据.这样也难怪他们会产生将CRUD这些操作放入对象中的念头. 如果你不能深刻理解oo, 那么我不推荐你使用o/r m, Table Gateway, Row Gateway才是你想要的东西.
作为一个O/R M框架,很重要的一点就是实现映射的透明性(Transparent),比较显著的特点就是在代码中我们是看不到SQL语句的(框架自动生成了),但是这并不是透明性的实质,详见Enterprise Persistence Design,这里所指的O/R M就是类似于此的框架.
4. POEAA中的相关概念
很多次发现有人错用其中的概念, 这里顺便总结一下:
1. Table Gateway
以表为单位的实体,基本没有行为,只有CRUD操作.
2. Row Gateway
以行为单位的实体,基本没有行为,只有CRUD操作.
3. Active Record
以行为单位的实体,拥有一些基本的操作自身数据的行为(如上例中的GetName),同时包含有CRUD操作.
其实Active Record最符合某些简单的需求, 接近于E/R m.
通常也有很多人把它当作O/R m.不过需要注意的是Active Record中是充满了SQL语句的(不像orm的SQL透明), 所以有人想起来利用O/R m来实现"Active Record", 虽然在他们眼里看起来很方便, 其实根本就是返祖.
用CodeGenerator来实现Active Record也许是一个比较好的方法.
4. Data Mapper
这才是真正的O/R m,Hibernate等等工具的目标.
5.O/R M需要关注的地方 (希望大家帮忙完善一下)
1. 关联以及与此相关的Lazy Load, O/R M是如何管理类之间的关联.当然这不仅于O/R M有关与设计者的设计水平也有很大关系.
2. O/R M对继承关系的处理.
3. O/R M对事务的支持.
4. O/R M对查询的支持.
以上观点仅属个人意见, 不过在大家讨论有关O/R M之前, 希望先就一些基本概念达成共识, 不然讨论下去会越离越远.
(建议: 如果对oo以及dp没有一定程度的了解, 最好别使用o/r m, dataset 加上codesmith或许是更好的选择)
Feedback
# re: O/R m 基本概念(欢迎指正) 回复
2005-07-04 16:27 by Cavingdeep不是没有发布稳定版本,就是有些功能太弱,如查询、1:N、
N:M!
我的观点:
假设有钞票,商店,一种设计是
钞票.使用(商店);
一种是:
商店.销售(钞票);
在这里我认为钞票是实体类,商店是操作类;
如果第一种设计在过了一个食堂的时候,那么就势必影响钞票的行为:
钞票.使用(食堂);
只有食堂和商店使用相同的接口,才能让钞票不必为后来的需求做修改,但这样对以前的开发水准将有较高的要求。
如果使用后一种设计,那么:
食堂.销售饭(钞票);
这个后来的需求建立在已有的设计“钞票”,所以不会影响以前的设计。
另外目前有两种设计思路:
1。 将行为赋予包含待数据的对象本身
2。 XXX对象仅包涵数据, 通过另一个XXXmanager来操作该对象。
第二种在soa中比较常见, 不过以上都不是本文主要讨论的问题, 希望大家的评论集中对orm的理解上上, 以上问题可以由谁再写一篇文章讨论。
Table Gateway、Row Gateway、Active Record、Data Mapper均是对象关系映射的实现模式,真正的对象关系映射目前是不存在的,所有的O/R Mapping方案都只不过是一个虚假的过渡品而已。严格来说,凡是能建立关系与对象之关的映射的,无论能力强弱,都可称之为O/R Mapping方案.
所谓的Hibernate也只是众多O/R Mapping解决方案相较更为广泛使用的一种策略,它本身并不能说明什么才是真的O/R。
】http://blog.joycode.com/uestc95/archive/2003/11/04/5176.aspx
O/R Mapping,陷阱还是苹果?
在JAVA的世界始终在讨论的一个问题是:EJB是否欺骗了我们?当然这样的问题就好像鸡生蛋蛋生鸡一样没有定论和结果,但是不容置疑的是EJB的确不是当初我们想像的那样好,世界上本来就没有救世主,一切还都要靠自己。而在.NET世界则更是如此,都说微软提供了开发人员所需要的一切,从而使得开发人员越来越贬值,但实际情况却恰恰相反,太多的东西他都没有提供,比如O/R Mapping机制,持久维护机制等等。
使用MS提供的免费午餐带来的代价就是:你别无选择,因为你也根本没有其他的选择,比如COM+,Remoting,再比如以后的Indigo。从另外一个角度来讲,这也未尝不是一件好事情,当然前提你没有发现JAVA世界的精彩。
上面的话其实没有开始这篇随笔的主题:O/R Mapping,陷阱还是苹果?只是开始的一瞬间,思维胡乱跳跃。其实还有一个更大的延伸话题是:OO世界是否是一个虚幻的世界?当然这就不是我所能探讨的话题了,你可以和OO大师们一论高低,
.NET 2.0将会提供O/R Mapping机制的实现,你自己看看就会发现他只是在和J2EE相靠拢,当然J2EE的O/R Mapping也是在向某种东西靠拢,究竟是什么呢?你当然会说是:高效开发,提升可延展性,降低需求变化给软件设计和编码带来的振荡。没错,的确是这样的。但是这样作并不是没有任何牺牲的,那就是增加编码的复杂度和工作量,毕竟宇宙间能量是守恒的! 是苹果还是陷阱,就要看这些牺牲是否值得了。这就不是一个是或者否能精确回答的问题了,通过精确的项目控制和人为能力,完全可以做到高效率,而不采用O/R Mapping,比如前提是不考虑多数据库支持。因为说到底,O/R Mapping机制提供的可延展性是非常有限的,他对于业务逻辑的支持基本上等于0,而我们大量的工作量都在业务逻辑部分。这也是我为什么有这样一个随笔的原因所在。我们在仔细分析了当前业务环境之后就要决定O/R Mapping是否值得去使用,如果你追求的高效率,而不是所谓的“优美设计”,那么就放弃吧。
比如我们高强度的ERP运算的时候,一定需要绕开O/R Mapping机制,否则等待我们的一定会是系统当机。而现在我发现越来越多的开发人员在刻意追求所谓的OO设计,尤其是.NET世界,虽然O/R Mapping算不上“过度设计”,但是本质一样。所有提供O/R Mapping机制的技术都会提供对象缓存技术,为什么?因为他知道这种构建实体和进行持久化的动作将会是非常耗费系统资源的,也就是说他们了解O/R Mapping所带来的问题,通过对象缓存技术来尽量抵消这个缺陷,但仅仅是“尽量”,所以我们开发或者分析设计人员更要明白的了解何时该绕过O/R Mapping!
不是说你运用OO技术和设计模式多么熟练就表明你的功力有多高,而是说做到正确辨别何时该用什么才是真正的高手。
不能接受这样的评述:
仔细想想我们为什么需要o/r m,无非是想利用oo的多态来处理复杂的业务逻辑, 而不是靠一堆的if else.
而现在在很多人的手上o/r m全变成了e/r m.他们不考虑对象的行为, 而全关注于如何保存数据.这样也难怪他们会产生将CRUD这些操作放入对象中的念头. 如果你不能深刻理解oo, 那么我不推荐你使用o/r m, Table Gateway, Row Gateway才是你想要的东西.
其实单纯为了O/R Mapping而O/R Mapping毫无意义。在完整的开发周期中,前面需要领域模型(ER模型或者UML模型,两者只是关注点不一样),后面有对业务层甚至表现层对O&R的消费。O/R Mapping有时候其实就是在面向对象与运行环境的元数据层的妥协而已。在某些特定情况下,对象这此仅仅只是一个数据容器并没有异化面向对象的本质。
直接通过模型来生成领域对象代码是为了提高开发的生产力。但是从模型中生成的代码往往都是“死对象”,都不包括行为。因为来自模型嘛。仅仅将这些对象作为数据容器或者关系容器也就足够了。
实体的行为,可以通过另外的对象来补充之。事实上,在实际开发中,单纯某个实体内部的行为少之又少,多态就更不需要了。
我对以上概念的理解:
对象:对于领域是抽象的,对于实体又是具体的概念
实体:一个元数据级别的概念,业务对象的描述器而已
关系:另外一个元数据级别的概念,聚合,合成,继承,关联,自引用,大概这么五种吧。你所谓的Table Gateway, Row Gateway是无法描述复杂关系的。
经典!
但有两点谈谈我的看法:
1、对ActiveRecord的理解不同意。
ActiveRecord本质上应该是领域模型,并不是实体+数据访问。
ActiveRecord可以包含几乎所有的领域逻辑,也可能只是一些面向数据的普通代码。
ActiveRecord通常是和数据库表同构的。一个包含了数据访问的领域模型。因为他们是同构的,数据映射不太复杂,所以不必要用到分离的Mapper。
2、ORM需要关注的可能还有:标识,延迟加载,查询。
个人观点,欢迎讨论!
# re: O/R Mapping 基本概念(欢迎指正) 回复
2005-07-05 11:38 by Nineteen@newsmth另外,多不多态,这是一个值得探讨的问题,有一些大师级指出多态是一种没事找事干的行为,纯属瞎折腾(不过,我觉得还是很有用的)。另外还包括继承之类的OO概念...也是非常值得争议的。目前就OO而言,也不是很令人满意,有理论背景因素,也有实践因素,还有目前科学技术水平的制约。O/R目前实际上有空中楼阁之嫌,所有的东西都不如我们一开始认为的那样好...还有待发展呐
# re: O/R Mapping 基本概念(欢迎指正) 回复
2005-07-16 16:59 by happyprogramworkjie:关键是有没有悬崖勒马,呵呵
看来各位的概念是已经背的滚瓜烂熟了,惭愧,惭愧
现在都说三层,表现层、业务层、数据访问层,这里不说表现层。我这里有三个类:OrderInfo、OrderDataServices、Order。其中,OrderInfo对应于这里描述的Entity,这个是可以自动化的(比如用CodeSmith生成),OrderDataServices在数据访问层,执行CRUD和其他一些访问数据库的操作,我估计只能部分自动化,难以达到100%自动化,如果根据业务逻辑,先写好部分存储过程,可能自动化程度会高一点(我这里所说的并不是将业务逻辑写进存储过程,而是将业务逻辑中最基础的一些数据操作写进存储过程),Order在业务层,就更难自动化了,当然可以少部分自动化。
再举个例子,UserInfo、UserDataServices、User,UserDataServices里除了有CRUD操作外,还有个GetPassword()方法,这个显然是根据业务逻辑而确定的,User类里有个Authentication()方法,数据库里肯定没有相关信息,来给这个User类自动生成Authentication()方法。
ORM就字面来看,是说对象与对象之间的关系,好像与数据没有很大联系,但我们在说ORM时却往往根数据库联系在一起,不知其最初是不是从数据而来的。
我水平有限,项目经验也很少,不知说的对不对。
ORM是对象-关系数据库映射的意思. 不是对象关系映射.
因为现在的编程模型多是oo模型,而数据库用的又都是关系型数据库, 所以才有了ORM的概念.
不过因为昨天有点事,我的回复还没写完,今天继续。
如果仅根据数据库,一般XXXXInfo、XXXXDataServices是可以生成的,但处于业务逻辑层的User类,还需要大量的业务信息(如来源于UML的信息)才能自动生成,那么应该如何做呢?一般都是将业务逻辑层类所需要的方法放到配置文件里,有ORM工具从配置文件中读取业务信息,从而生成业务逻辑层的类。这里对象与对象之间的关系就体现在配置文件中。
我感觉如果仅仅生成类似XXXXInfo、XXXXDataServices类,用CodeSmith就不错。如果也要生成Biz类,看来要用ORM工具了。
不知我的理解对不对,请指教。
1。 o/r m不是代码生成器。
2。 o/r m关注于持久层的操作, 业务逻辑与之无关。它不会自动生成业务代码。
3。 o/r m的目的在于让你关注业务逻辑的编写,而较少的考虑数据保存。
你的理解似乎有点偏差。
如果仅根据数据库,一般XXXXInfo是可以生成的,但处于数据访问层的XXXXDataServices类只能部分生成,还需要大量的业务信息(如来源于UML的信息)才能自动生成,那么应该如何做呢?一般都是将业务逻辑层类所要用到的、XXXXDataServices类的方法描述,放到配置文件里,由ORM工具从配置文件中读取这些信息,从而生成数据访问层的类。
请看看对不对?
参考一下这个吧.
http://www.alphatom.com/content/view/267/69/
# re: O/R Mapping 基本概念(欢迎指正) 回复
2005-09-07 11:16 by yyanghhongspring是把service和domain object, Data access object连在一起的好架构, 比如用他来配置service里的transaction.
有人说DTO是用来实现传递数据在remote layer之间, 其实是多此一举, hibernate里可把domain object转为detched object来达到这个目的, 用web service的话也可用xml attribute来serialize domain object.
大多人做OO总是喜欢钻牛角尖,许多人认为关系数据库的实体模型不是OO模型,这一点来说无疑是正确的,对于域模型来说,域对象和数据库中的实体对象不完全是一一对应的,于是有了各种各样的映射模型出现。但是他们忽略了一个事实,那就是在OO世界中任何东西都可以表示为对象,数据库也不例外,数据库是对象,数据库中的表同样也是,况且很多业务更接近数据库的关系模型,如日常中的报表之类(面向对象数据库系统之所以不能广泛流行的原因恐怕这也是其中之一吧?)。
当我们换一种角度来重新审视数据库的时候,也就是说当你把数据库看作一个对象的时候,那么对象之间的关系是否会更清晰些?
日前看了DLinq(C#3.0)项目的实现,个人觉得MS的思路是正确的,这也是DLinq值得期待的一个理由。如果DLinq正是发布之时,我想上面的讨论大多数都显得很多余。另外,注意一个事实,那就是DLinq并不只是ORM。