【发布时间】:2013-02-01 14:18:33
【问题描述】:
我想基于业务密钥而不是对象身份覆盖等于,但我无法使其与休眠一起使用。
我知道有人问过类似的问题,阅读答案(如 this)有助于理解不破坏等价关系,使用 instanceof 代替 getClass,使用 getter 代替字段引用。等等,但我的 equals/hashCode 实现仍然会破坏地图的休眠人口。
我没有收到错误,hibernate 将所有 3 个实体正确保存在数据库中的映射中,但是当我再次读取带有映射的实体时,它只读取 1 而不是全部 3。 hibernate记录的sql在mysql中执行时选择正确的所有3个实体。
该项目基于 Spring 3.2.1、Hibernate 4.1.5 和 JPA 注释
更新
在调试休眠时,它似乎为 3 个映射实体中的每一个调用 hashCode,但是除了休眠生成的 id 之外,所有值都是空的。因此,由覆盖方法计算的 hashCode 始终相同。我想这就是为什么只有一个实体被添加到地图中的原因。但是我不明白为什么hibernate会在从数据库加载数据之前计算hashCode?p>
示例
在下面的示例中,我在一个包含 3 个简单实体的项目中重现了该错误(所有实体都具有休眠生成的 id):
- 项目
- 语言
- 语言详情
Item 有一个 LanguageDetails 的 Map,其中 Language 是关键:
@OneToMany(mappedBy="item", orphanRemoval=true, cascade=CascadeType.ALL, fetch=FetchType.EAGER)
@MapKey(name="language")
private Map<Language, LanguageDetails> languageDetails = new TreeMap<Language, LanguageDetails>();
Language 中的业务键是一个名为code 的字符串。我对覆盖 equals 的最佳猜测是使用 eclipse 生成 equals/hashCode(并用 instanceof 和 field refs. 替换 getClass):
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((getCode() == null) ? 0 : getCode().hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (!(obj instanceof Language))
return false;
Language other = (Language) obj;
if (getCode() == null) {
if (other.getCode() != null)
return false;
} else if (!getCode().equals(other.getCode()))
return false;
return true;
}
以下集成测试使用上述 equals/hashCode 失败,但没有成功:
Item item = new Item();
Language english = languageService.getByCode("en");
Language german = languageService.getByCode("de");
Language spanish = languageService.getByCode("es");
item.getLanguageDetails().put(english, new LanguageDetails(item, english, "ice cream"););
item.getLanguageDetails().put(spanish, new LanguageDetails(item, spanish, "helado"););
item.getLanguageDetails().put(german, new LanguageDetails(item, german, "eis"););
//save - stores all 3 languageDetails correct in mysql
int id = itemService.create(item);
//read - loads only 1 languageDetails (de)
Item readItem = itemService.getById(id);
//java.lang.AssertionError: expected:<3> but was:<1>
Assert.assertEquals(item.getLanguageDetails().size(), readItem.getLanguageDetails().size());
我做错了什么?
【问题讨论】:
标签: hibernate orm map overriding equals