【问题标题】:How to override equals for a key in a Hibernate map?如何覆盖 Hibernate 映射中键的等于?
【发布时间】: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


    【解决方案1】:

    我花了将近一个星期的时间来调试、编写解决方法并试图理解这个问题,在我越来越绝望的试错尝试中,我找到了解决方案:

    我将休眠版本从 4.1.5 更改为 4.1.8,我所有的痛苦都消失了。这是休眠中的一个错误,已在版本4.1.7 中修复...

    下次我一定会早点检查错误报告...

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-07-12
      • 1970-01-01
      • 2011-03-14
      • 1970-01-01
      • 2020-08-21
      • 1970-01-01
      • 2013-04-09
      • 1970-01-01
      相关资源
      最近更新 更多