论坛首页 Java企业应用论坛

实现实体的hashCode,equals时候请注意

浏览 47738 次
该帖已经被评为精华帖
作者 正文
   发表时间:2004-11-23  
Readonly 写道
TimePoint 和 Duration这种设计的出处在domian driven design这本书的part iii:
http://www.domaindrivendesign.org/articles/blog/evans_eric_sweating_the_small_stuff.html

有一个open source项目就是实现它的:
http://timeandmoney.sourceforge.net/

这种东西在Hibernate里而言, 只是一个UserType, 是一个Entity的属性, 而不会是一个完整的Entity......


    谢谢你贴出出处。

   至于如何用UserType实现,我并没有采用,这个实现是我前年年底的时候实现的,直接用的就是实体。最初用lido(jdo)实现,后来用hibernate(好像当时初学吧)。深入没有研究, 期待你的实现参考
0 请登录后投票
   发表时间:2004-11-23  
weihello 写道

   “我认为id为null是否不等,是个业务需求”,我不是很明白。呵呵,抱歉。

一个实体对象,在不同的应用场景下,判断相等的标准未必固定不变,这时候就不能简单依赖于equals().
你举的这个例子,id为null的object之间如何比较的?

weihello 写道
好像这个帖子的原意就是为了解决你这个问题的。

就是因为这个问题,我才对这种方式保持警惕.后又觉得只比较id对于处理父子关系会非常方面,所以就彻底抛弃掉了.
真有你说的场景,我会考虑再加上,可还是没有碰上
0 请登录后投票
   发表时间:2004-11-23  
Readonly 写道
weihello 写道

如果实体本身带有行为(不是get,set),这种情况就更加频繁发生了。参考

然后赋值, 然后交互, 接着保存, 不就把新的时间区间弄好了么?
你举的这个怎么看也没有说明id为null的object之间的相等比较呀???


   这是你后来编辑的,无意间看到。

     怎么没有比较呢,几个时间段,完全可以录入的啊! 为什么非得一个个处理呀,这里关心的是starttime和endTime呀。
  
    不知道你有没有在网页上做过输入列表,每行输入其实都是一个TO,然后提交,一次性持久。
   
      这个问题我想我们还是到此为之吧。 其实你担心的要么就是
1、贪图便利
其实最后还是不便利,每种ID策略要一个超类(?),减少一些可操作性,组件则区别对待,脱离Hibernate你这个实现无效(呵呵,请不要强调现在是hibernate,注意我们都是程序员).

2、效率,学robbin一句话,请拿出具体案例,说明大幅度减低效率给我看;

3、还有yucai说的,“就是因为这个问题,我才对这种方式保持警惕”, 如果问题

确实出在这里,我可以一次性全部解决,改动也只有一处。 而其说的“真有你说

的场景,我会考虑再加上,可还是没有碰上”却是真正的地雷。 显然,他这样做是

本末倒置,为了贪图方便牺牲其他的一些可操作性。
0 请登录后投票
   发表时间:2004-11-23  
weihello 写道
至于如何用UserType实现,我并没有采用,这个实现是我前年年底的时候实现的,直接用的就是实体。最初用lido(jdo)实现,后来用hibernate(好像当时初学吧)。深入没有研究, 期待你的实现参考


http://forum.iteye.com/viewtopic.php?t=9035

在那个例子里面你可以看到, 一次提交多个, 再进行持久不是什么问题, 只需要在save以前,让这多个对象交互好就行了.

偶的目的就是: 贪图便利
而且实际项目中, 偶们规定不要用HashSet/HashMap之类的Hash容器来存放对象, one-to-many / many-to-many都是用List来处理的, 所以偶的BaseEntity只override掉equals()方法, hashCode()是不去实现的, 是不是贪图便利得超出你的想象? hoho.
0 请登录后投票
   发表时间:2004-11-23  
Readonly 写道
weihello 写道
至于如何用UserType实现,我并没有采用,这个实现是我前年年底的时候实现的,直接用的就是实体。最初用lido(jdo)实现,后来用hibernate(好像当时初学吧)。深入没有研究, 期待你的实现参考


http://forum.iteye.com/viewtopic.php?t=9035

在那个例子里面你可以看到, 一次提交多个, 再进行持久不是什么问题, 只需要在save以前,让这多个对象交互好就行了.

偶的目的就是: 贪图便利
而且实际项目中, 偶们规定不要用HashSet/HashMap之类的Hash容器来存放对象, one-to-many / many-to-many都是用List来处理的, 所以偶的BaseEntity只override掉equals()方法, hashCode()是不去实现的, 是不是贪图便利得超出你的想象? hoho.

list?
你在映射文件里是list还是bag?
list要多一个index列,单向的bag效率又太低,有时候也不得不用set呀
0 请登录后投票
   发表时间:2004-11-23  
Readonly 写道
shenli 写道
Readonly,你的后面的这种写法在特定场合不管会不会遇到错误,都已经违反了hashCode基本的原则,当两个对象equals方法成立的时候,必须得到同样的散列码

嗯, 偶做错了, 这样会导致: 先做了hashCode操作以后一个未被持久化的object, 和再从数据库里面获得的object虽然equals, 但是hashCode不一样了, 违反了最基本的原则, 

shenli 写道
既然一个对象是可变的,我不知道为什么要保证他的散列码不变呢?这个测试(当然不知道谁规定的)这种可重新读出有意义吗?本来在java环境下就没这个要求,不过是hibernate一种特殊的主键产生策略导致的问题?

嗯, java规范里面好像是没有这样的规定, 但是作为一种特定的可持久化对象 (如hibernate这样对应到数据库里的一个row), 在equals的语义上带来的后果: 2个从不同session里面load的对应到同一row的object, 你认为它们是相等还是不相等呢?

shenli 写道
刚刚download了hibernate in acdtion的代码,他是在每个entity用业务字段生成的equals和hashCode。原来我也是在一个父类或者mixin中用主键做的,唯一的不同就是用this.getclass == object.getclass取代你的x instance of xxxx

昨天偶问过看过Hibernate in action的人了, 他说书里面有3种做法:
1. 就是偶说的这种用无意义主键做hashCode/equals
2. 就是weihello用的所有值做hashCode/equals
3. 用一个(或者几个)相对稳定的业务字段做hashCode/equals (比如user, 就用userName).

hibernate 推荐的是第3种, 按照这种推荐的做法, 就不会出现以上说的所有问题了, 看起来是最佳的实践了.

我还是会坚持我的做法,因为我知道如何去避免潜在的陷阱,至于所谓的基本的原则嘛,嘿嘿,为了可以偷懒。。。
0 请登录后投票
   发表时间:2004-11-23  
CafeBabe 写道

list?
你在映射文件里是list还是bag?
list要多一个index列,单向的bag效率又太低,有时候也不得不用set呀

映射文件里面用bag, 单向的bag为什么效率低呢?
0 请登录后投票
   发表时间:2004-11-23  
bag在更新时候的效率低哦。
0 请登录后投票
   发表时间:2004-11-23  
http://forum.hibernate.org/viewtopic.php?t=935732
使用cache的时候出现bug
0 请登录后投票
   发表时间:2004-11-23  
Readonly 写道
CafeBabe 写道

list?
你在映射文件里是list还是bag?
list要多一个index列,单向的bag效率又太低,有时候也不得不用set呀

映射文件里面用bag, 单向的bag为什么效率低呢?

因为bag中的元素是可重复的,对单向bag的update,delete操作总是先delete原先所有的
纪录,然后再insert现有的数据。
不过双向的bag缺是效率最高的,因为你往bag里add一个元素是不需要
初始化这个bag的。
说得有点乱 ,看看文档,再自己试试就清楚了。
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics