发表评论
个人偏好第一种。
原因:虽然第二种更符合OO思想,但是第二种简单明了。
第二种!
性能上的优劣完全可以忽略不计(不是指性能下降不多,而是指这种性能上的牺牲换来的是应对变化时的方便)
BolgId相对于Blog对象哪个是更不易变化的?当然是Blog对象
既然一种设计更符合OO思想,那么我们为什么不用它呢?
毫无疑问绝对是第二种啊!这个难道到现在还有疑问吗?
性能上有“延迟加载”啊,还有“二级对象的缓存”,这两项功能是hibernate在实际项目中必须使用的。
#4楼 [
楼主]2006-06-20 07:59 |
@蔡克伦
@麒麟.NET
同感!
#5楼 [
楼主]2006-06-20 08:00 |
@CHNBin
没看明白:-)
“个人偏好第一种,虽然第二种更符合OO思想,但是第二种简单明了”
我也觉得应该用第二种。
因为在第一种模式中加载了两个ID之后,相当于和Blog,Category还是没有任何关系——需要Blog和Category的内容的时候,依然需要使用相应的ID来Load——那样还有什么意义呢?还不如直接用store procedure得了。
在性能上的损失也应该不会很大。第一,我们可以使用Lazy Load,第二,从实际使用的角度来讲,一篇文章和一个Blog以及一个Category的关系通常不会改变,因此使用Cache可以在最大程度上消除性能上的损失。
如果简单的第一种做法,还是基于DB的R->O的开发模式,这种做法不是OO罢
第二种确实是效率上肯定比第一种差一点,即使是通过某种相应的Lazy读取或者是Cache。
而且如果一个对象特别复杂的话,可能复杂属性相对很多,性能下降是不可避免的,即使是用了这样那样的方式。
但是我们有的时候更关心的是程序的可维护性,而不是计较这么一点资源。
BTW,我下载了Nhibernate的源码,编译通不过,汗……,少了个把文件……。
@蔡克伦
从OO设计上来说,那肯定是第二种。
不过你说到Lazy Load,我就想起我一个同学用(Hibernate),他说用Lazy Load的方法获取页面上的数据,但是就是因为需要Lazy Load,导致数据库连接长期占用,他说Java里面的那些连接池组件也都有或多或少的问题,导致网站支持的并发访问很少。
这是他遇到的。
不知道你们有没有遇到,怎么解决?或者怎么避免?
类似例子中Blog Category这种典型的多对一关系
实际应用中对这种枚举表字段需要进行级联更新的情况很少
俺一般在entity类中同时写
[Property]
public int BlogId
{
get{ return _blogId;}
set{ _blogId = value;}
}
private int _categoryId;
[Property]
public int CategoryId
{
get{ return _categoryId;}
set{ _categoryId = value;}
}
[Property]
public Blog Blog
{
get{ return _blog;}
}
private Category _category;
[Property]
public Category Category
{
get{ return _category;}
}
hbm文件的
<property name="CategoryId" />
<property name="BlogId" />
不动
<many-to-one name="Category" column="CategoryId" insert="false" update="false" />
仅作为加载
可惜nhibernate 不支持属性lazy-load
#13楼 [
楼主]2006-06-20 11:10 |
@hoverfly
谢谢:-)
这个问题值得初用ORM的朋友注意,不小心有可能就会按照第一种用法去用了。
问个业务实体的问题
业务实体暴露在业务规则中是合理?这东西在设计时非常头痛,很多情况下为了方便直接把业务实体中暴露在业务规则中了;但这样我感觉很不合理,业务实体在很多情况并不只是为一个业务规则服务,一旦业务实体暴露在业务规则中就会导致业务规则有歧义.
不知道各位有什么看法?
个人比较倾向于第二中设计方案,虽然相比于第一种设计方案性能上可能有所降低,但是第二种方法在使用的时候却很方便
我们是俩个都放。
有BlogId,也有Blog对象。
@henry
如果这里的实体只是POJO不是ar模式
个人认为不仅在业务层暴露没问题
应该划到Common里让各层饮用都可以
参见duwamish
IMHO, the first solution will unavoidable lead to some service/manager/dao class to write business rules, then leads to data procedure method design, it is not OO.
the second soultion will be posssible to make it as POJO, with the underline business rules inside the object, which is a pure oo design.
Does this actually mean AR pattern is not really an OO design?
But I still doubt how much do we really need OO for most of database application.
@gozh2002
Does this actually mean AR pattern is not really an OO design?
何出此言?
@TerryLee
用DiscriminatorColumn来把多个实体持久化到一个表里,必须把父类定义成ActiveRecord吗?我试验没有做定义,结果出了一些奇怪的问题。
个人观点,虽然第二种看起来比较适合OO的思想,但是有一点,作为database driven的程序,这样做在R-O的时候是不是还是比较牵强?
#21楼 [
楼主]2006-06-20 18:10 |
@hoverfly
是的,试验出什么问题了?
#22楼 [
楼主]2006-06-20 18:12 |
@维生素C.NET
我不这么认为,能否解释一下呢?
@TerryLee
因为父类使用了泛型,如果作为ActiveRecord的话会出现错误,所以只好只把子类定义为ActiveRecord。保存的时候一切正常,但是查找的时候发现DiscriminatorColumn没有起作用,查看数据库,DiscriminatorColumn是被正确记录了的。
别这样想。用ID还是用实体是具体的系统决定的(不过大多数系统都是要实体的)
你的
[PrimaryKey(PrimaryKeyType.Native, "PostId")]属性
不是也是数据库的么
#25楼 [
楼主]2006-06-21 08:06 |
@Zhongkeruanjian
PostID是主键,而其它的两个ID则是外键
#27楼 [
楼主]2006-06-21 14:09 |
@双鱼座
在David Hayden的文章中看到他这样写,所以拿出来讨论一下,不过初用ORM很有可能就会写成第一种:-)
@双鱼座
有一点想法不太一样,对于有连接池的情况,多次连接比长时间占用应该更有效率。
还有:
举个例子吧。你要加载某段时间所有购买XXX产品的订单项。如果是LazyLoad就只需要加载订单项,但是当需要获取订单项所在订单的日期的时候你不得不去再次启动数据库连接加载这个订单项所在的订单。但是如果你要加载某段时间的所有订单,我不一定关心每个订单所有的订单项。如果需要可以手动或自动加载,但不能叫LazyLoad。
这不是Lazy-Load吗?
抱歉TerryLee,这有点离题:P
就拿上面的例子说,一个Blog对象里应该有一个IList Posts成员。而Post下又可以有其他对象。如果是没有Lazy-Load的话,得到一个Blog对象不就会要查询它下面的所有Post以及它们的下层对象吗?这样会多很多查询。
@hoverfly
不太明白你的意思。如果你要加载满足某个条件的所有订单项,我可以加载这些订单项,然后马上加载这些订单项所引用的订单(这是立即加载而不是lazyLoad)。这是引用的情况。
对于组合的情况,如果你要加载满足某个条件的订单,我不一定会立即加载每个订单的订单项集合(这并不需要LazyLoad)。如果需要的话,我会手工加载,但是我会加载全部需要的订单项而不会每个订单的订单项加载一次,这是个策略问题。其实,我也同意并不是因为连接池或者连接的问题,而是在LazyLoad时你有可能将1个SQL可以加载的过程演变成300个SQL。例如如果你有300个订单满足你指定的条件,LazyLoad时,你只能为每个订单加载一次订单项,这样的确需要加载300次,而本来可以用一次查询加载全部的订单项的。
我这里否决LazyLoad是基于这样一个前提:“一对多”的实体,其中的“一”也不是孤立的。
@双鱼座
对于组合的情况,如果你要加载满足某个条件的订单,我不一定会立即加载每个订单的订单项集合(这并不需要LazyLoad)
好像有些ORM框架是直接把每个订单项的集合都加载的吧(不使用Lazy-Load时),至少ActiveRecord是这样。我感觉这样可能效率会有问题(所以需要Lazy-Load),但是很符合OO的原则。如你所说的情况,怎么做到一次查询得到所有300个订单的订单项呢,用in查询吗?怎么让找到的订单项和300个订单保持关系呢?
#32楼 [
楼主]2006-06-22 08:05 |
@hoverfly
呵呵,没什么,讨论问题嘛:-)
我觉得2种在不同的情况下运用不同,我个人认为第2种比较直观一些,但是在有的时候没有必要,比如说在一些移动设备开发上(或者说是内存受限)的情况下第一种情况可能回更好一些。
还有上面说的延迟加载的问题,其中的一个目的就是解决这样一个问题。
引用 hoverfly 的话: 就拿上面的例子说,一个Blog对象里应该有一个IList Posts成员。而Post下又可以有其他对象。如果是没有Lazy-Load的话,得到一个Blog对象不就会要查询它下面的所有Post以及它们的下层对象吗?这样会多很多查询。
我还是没太清楚该怎么处理这个问题。
Post实体里有Blog对象
Blog实体里有Posts列表对象(可能是IList)
就拿上面的例子来说, 第2种方式, 我要查询300条Article对象列表显示出来, 其中的Blog和Category对象是否也要针对每个Article做300次的查询, 这样不是大大影响效率吗? (我用NHibernate做的实验确实如此, 不知道我在使用上有没有问题.)
楼主的例子算是个片段,我想知道Create应该怎么去做呢?
Create一条Post记录,必定是要写BlogId这个字段的,是不是要覆写base.Create方法?在这个方法里把_blog.BlogId取出来往库里写?
楼主,你的修正会不会有这样的一个问题:
在表的设计上,article这个表少不了有个blogId字段对吧?
这样的话,我想按blog检索,Article应该提供一个FindByBlog的方法对吧?
它的参数按OO的思想应该是Blog(是blogId也无所谓,这不是重点)
但问题来了
public static Article[] FindByBlog(Blog blog)
{
return FindAllByProperty("xxx", blog.Id);
}
上面代码里的xxx应该怎么写呢?xxx应该是Article里的一个属性,可是你的修正后的类里只有一个
[Property]
public Blog Blog
这样岂不是不能按Blog检索文章了?
你的系列文章我还没看完,有没有解决之道?
楼主及众家兄弟啊,为什么我在程序里加入了
[Property]
public qcrsoft.Blog Blog
。。。。。
后会提示
You can't use [Property] on Article.Blog because qcrsoft.Blog is an active record class, did you mean to use BelongTo?
啥意思捏?