hibernate/webapp 上下文中的对象相等
如何处理 hibernate 管理的 java 对象的对象相等性?在“休眠实践”一书中,他们说人们应该优先使用业务键而不是代理键。
大多数时候,我没有商务钥匙。想想映射到一个人的地址。地址保存在 Set 中并显示在 Wicket RefreshingView 中(使用 ReuseIfEquals 策略)。
我可以使用代理 id 或使用 equals() 和 hashCode() 函数中的所有字段。
问题是这些字段在对象的生命周期中会发生变化。要么是因为用户输入了一些数据,要么是由于在 OSIV(在视图中打开会话)过滤器内调用 JPA merge() 导致 id 发生更改。
我对 equals() 和 hashCode() 契约的理解是,它们在对象的生命周期内不应改变。
到目前为止我已经尝试过:
- 基于 hashCode() 的 equals() ,它使用数据库 id(如果 id 为 null,则使用 super.hashCode() )。问题:新地址以空 id 开头,但在附加到某个人时会获得一个 id,并且此人会在 osiv-filter 中被 merged() (重新附加)。
- 当第一次调用 hashCode() 时,惰性计算 hashcode 并将该 hashcode 设置为 @Transitional。不起作用,因为 merge() 返回一个新对象并且哈希码不会被复制。
我认为我需要的是在对象创建期间分配的 ID。我在这里有什么选择?我不想引入一些额外的持久属性。有没有办法明确告诉 JPA 为对象分配 ID?
问候
How do you handle object equality for java objects managed by hibernate? In the 'hibernate in action' book they say that one should favor business keys over surrogate keys.
Most of the time, i do not have a business key. Think of addresses mapped to a person. The addresses are keeped in a Set and displayed in a Wicket RefreshingView (with a ReuseIfEquals strategy).
I could either use the surrogate id or use all fields in the equals() and hashCode() functions.
The problem is that those fields change during the lifetime ob the object. Either because the user entered some data or the id changes due to JPA merge() being called inside the OSIV (Open Session in View) filter.
My understanding of the equals() and hashCode() contract is that those should not change during the lifetime of an object.
What i have tried so far:
- equals() based on hashCode() which uses the database id (or super.hashCode() if id is null). Problem: new addresses start with an null id but get an id when attached to a person and this person gets merged() (re-attached) in the osiv-filter.
- lazy compute the hashcode when hashCode() is first called and make that hashcode @Transitional. Does not work, as merge() returns a new object and the hashcode does not get copied over.
What i would need is an ID that gets assigned during object creation I think. What would be my options here? I don't want to introduce some additional persistent property. Is there a way to explicitly tell JPA to assign an ID to an object?
Regards
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
使用实体的
id
并不是一个好主意,因为瞬态实体还没有 id(并且您仍然希望瞬态实体可能等于持久实体)。使用所有属性(除了数据库标识符)也不是一个好主意,因为所有属性都不是身份的一部分。
因此,实现平等的首选(也是正确的)方法是使用业务键,如Java Persistence with Hibernate中所述:
也许我错过了一些东西,但对于地址来说,业务键通常由街道号码、街道、城市、邮政编码和国家/地区组成。我认为这没有任何问题。
以防万一,Equals And HashCode 是另一本有趣的读物。
Using the
id
of an entity is not a good idea because transient entities don't have an id yet (and you still want a transient entity to be potentially equal to a persistent one).Using all properties (apart from the database identifier) is also not a good idea because all properties are just not part of the identity.
So, the preferred (and correct) way to implement equality is to use a business key, as explained in Java Persistence with Hibernate:
Maybe I missed something but for an Address, the business key would typically be made of the street number, the street, the city, the postal code, the country. I don't see any problem with that.
Just in case, Equals And HashCode is another interesting reading.
也许一个
transient
属性可以做到这一点?这样你就不用担心坚持的问题了。像这样:
Maybe a
transient
property would do it?That way you don't have to worry about the persistence. Like this:
我过去常常这样做:equal 和 hashcode 在设置后使用键,否则 equals 使用基本实现(又名 ==)。如果
hashcode()
返回super.hashcode()
而不是 0,它也应该可以工作。I use to do it that way: equal and hashcode use the key when it has been set, otherwise equals uses the base implementation (aka ==). It should work too if
hashcode()
returnssuper.hashcode()
instead of 0.问题是您多久可能会出现多个未保存的对象,这些对象可能是需要放入集合或地图中的重复项?对我来说,答案几乎永远不会,所以我对未保存的对象使用代理键和 super.equals/hashcode。
业务密钥在某些情况下是有意义的,但它们可能会导致问题。例如,如果两个人住在同一个地址怎么办 - 如果您希望它成为数据库中的一条记录,那么您必须将其作为多对多进行管理,并且失去级联删除它的能力,因此当最后一个记录时居住在那里的人被删除,您必须做额外的工作才能删除该地址。但是,如果您为每个人存储相同的地址,那么您的业务密钥必须包含人员实体,这可能意味着您的 equals/hashcode 方法中的数据库命中。
The question is how often are you likely to have multiple unsaved objects that might be duplicates that need to go into a set or map? For me, the answer is virtually never so I use surrogate keys and super.equals/hashcode for unsaved objects.
Business keys make sense in some cases, but they can cause problems. For example, what if two people live at the same address - if you want that to be one record in the database, then you have to manage it as a many-to-many and lose the ability to cascade delete it so when the last person living there is deleted, you have to do extra work to get rid of the address. But if you store the same addresss for each person then your business key has to include the person entity, which may mean a database hit inside your equals/hashcode methods.
感谢您的所有意见。我决定使用代理键并在对象创建时提供这些代理键。这样我就可以远离所有那些“很少”改变的东西,并拥有一些坚实的身份基础。第一次测试看起来相当不错。
感谢大家抽出时间。不幸的是,我只能接受一个答案作为解决方案,我会选择帕斯卡,因为他为我提供了很好的阅读;)
享受
Thanks for all your input. I decided to use surrogate keys and provide those right at object creation time. This way i stay clear of all that 'rarely' changing stuff and have something solid to base identity on. First tests look rather good.
thank you all for your time. Unfortunately, i can only accept one answer as solution i will take Pascals, as he provided me with good reading ;)
enjoy