ber*_*ert 13 java wicket hibernate equality
你如何处理由hibernate管理的java对象的对象相等性?在"hibernate in action"一书中,他们说人们应该支持商业密钥而不是代理密钥.
大多数时候,我没有业务密钥.想一想映射到一个人的地址.地址保存在一个Set中,并显示在Wicket RefreshingView(具有ReuseIfEquals策略)中.
我可以使用代理id或使用equals()和hashCode()函数中的所有字段.
问题是那些字段在生命周期中对象变化.要么是因为用户输入了一些数据,要么由于在OSIV(在视图中打开会话)过滤器内调用JPA merge()而导致id发生变化.
我对equals()和hashCode()契约的理解是那些在对象的生命周期内不应该改变的.
到目前为止我尝试了什么:
我需要的是在我认为在对象创建期间分配的ID.这里有什么选择?我不想引入一些额外的持久属性.有没有办法明确告诉JPA为对象分配ID?
问候
Pas*_*ent 15
使用id实体不是一个好主意,因为瞬态实体还没有id(并且您仍然希望瞬态实体可能等于持久实体).
使用所有属性(除了数据库标识符)也不是一个好主意,因为所有属性都不是标识的一部分.
因此,实现相等性的首选(和正确)方法是使用业务键,如Java Persistence with Hibernate中所述:
使用业务键实现相等性
要获得我们建议的解决方案,您需要了解业务密钥的概念.业务键是属性或属性的某种组合,对于具有相同数据库标识的每个实例都是唯一的.从本质上讲,如果您没有使用代理主键,那么它将是您使用的自然键.与自然主键不同,业务键永远不会变化的绝对要求 - 只要它很少变化,这就足够了.
我们认为基本上每个实体类都应该有一些业务键,即使它包含了类的所有属性(这适用于某些不可变类).业务密钥是用户认为唯一标识特定记录的内容,而代理密钥是应用程序和数据库使用的密钥.
业务键等式意味着equals()方法仅比较形成业务键的属性.这是一个完美的解决方案,可以避免前面描述的所有问题.唯一的缺点是,首先需要额外考虑识别正确的业务密钥.无论如何都需要这种努力; 如果数据库必须通过约束检查确保数据完整性,则识别任何唯一键很重要.
对于User类,
username是一个很好的候选业务键.它永远不会为null,它与数据库约束是唯一的,并且它很少变化,如果有的话:Run Code Online (Sandbox Code Playgroud)public class User { ... public boolean equals(Object other) { if (this==other) return true; if ( !(other instanceof User) ) return false; final User that = (User) other; return this.username.equals( that.getUsername() ); } public int hashCode() { return username.hashCode(); } }
也许我错过了一些东西,但是对于一个地址,商业密钥通常由街道号码,街道,城市,邮政编码,国家组成.我没有看到任何问题.
以防万一,Equals和HashCode是另一个有趣的读物.
| 归档时间: |
|
| 查看次数: |
4873 次 |
| 最近记录: |