Hibernate的PersistentSet不使用hashCode/equals的自定义实现 [英] Hibernate's PersistentSet not using custom implementations of hashCode/equals

查看:43
本文介绍了Hibernate的PersistentSet不使用hashCode/equals的自定义实现的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所以我有实体书

public class Book {
  private String id;
  private String name;
  private String description;
  private Image coverImage;
  private Set<Chapter> chapters;

  //Sets & Gets

  @Override
  public boolean equals(Object o) {
    if (this == o) return true;
    if (!(o instanceof Book)) return false;
    Book book = (Book) o;
    return Objects.equals(name, book.name) &&
            Objects.equals(description, book.description) &&
            Objects.equals(image, book.image) &&
            Objects.equals(chapters, book.chapters);
  }

  @Override
  public int hashCode() {
    return Objects.hash(name, description, image, chapters);
  }
}

实体章节

public class Chapter {
  private String id;
  private String title;
  private String number;
  private LocalDate releaseDate;
  private Set<Distributor> distributors;

  //Sets & Gets

  @Override
  public boolean equals(Object o) {
    if (this == o) return true;
    if (!(o instanceof Chapter)) return false;
    Chapter chapter = (Chapter) o;
    return Objects.equals(title, chapter.title) &&
            Objects.equals(number, chapter.number) &&
            Objects.equals(releaseDate, chapter.releaseDate) &&
            Objects.equals(distributors, chapter.distributors);
  }

  @Override
  public int hashCode() {
    return Objects.hash(title, number, releaseDate, distributors);
  }
}

和一个分销商实体

public class Distributor {

  private String id;
  private String name;
  private Image logoImage;

  //Sets & Gets

  @Override
  public boolean equals(Object o) {
    if (this == o) return true;
    if (!(o instanceof Distributor)) return false;
    Distributor that = (Distributor) o;
    return Objects.equals(name, that.name) &&
            Objects.equals(logoImage, that.logoImage);
  }

  @Override
  public int hashCode() {
    return Objects.hash(name, logoImage);
  }
}

我有新老章节的 List< Chapter> ,我只需要在本书中添加新的章节即可.Hibernate使用其自定义实现 PersistentSet 获取并填充数据库中所有章节的 Set< Chapter> .

I have a List<Chapter> of old and new chapters and I have to add only the new ones to the Book. Hibernate fetches and populates the Set<Chapter> with all the chapters in the database using its custom implementation PersistentSet.

我要解决的问题是仅添加列表中PersistentSet中不存在的那些章节.但是我为此,因为Chapter不使用id字段来计算hashCode/equals,所以我可以将List中的所有章节添加到PersistentSet中,并且结果应该是一个Set,它从列表中排除已经存在并包括在内的那些章节那些不在集合中.好吧...这没有发生.

The problem I'm trying to solve is add only those chapters from the List that are not present in the PersistentSet. For this I though, as Chapter does not uses the id field to calculate the hashCode/equals I could just add all the chapters from the List to the PersistentSet and the result should be a Set that excluded those from the list that already exists and included those that are not in the set. Well... this is not happening.

Hibernate的 PersistentSet 没有使用我为 Distributor 实体定义的hashCode/equals函数,而是使用了它的一些内部实现,从而导致List和Set中的章节具有不同的hashCodes,并且不等于.让我们从列表 lChapter 中调用一个章节,并从PersistentSet psChapter 中调用一个章节,并假定它们除了ID之外都是相等的.如果我愿意

Hibernate's PersistentSet is not using the hashCode/equals function I defined for the Distributor entity but some internal implementation of it, resulting in the Chapters from the List and Set having different hashCodes and been not equals. Lets call a chapter from the List lChapter and a chapter from the PersistentSet psChapter and assume they are equals except for the Id. If I do

lChapter.equals(psChapter); //True

但如果我这样做

psChapter.equals(lChapter); //False

如果我愿意

book.getChapters().addAll(chapters);

成为具有20章的附加实体和具有21章的列表的实体,结果是包含41章的集合.

Being book an attached entity with 20 chapters and chapters the List with 21 chapters the result is a set with 41 chapters.

我在这里做错了吗?我发现这是一个非常琐碎的问题,但是我还没有找到不涉及我浏览列表并在添加之前检查其中是否包含解决方案的解决方案.这是我负担不起的不必要的额外步骤.

I'm I doing something wrong here? I find it been a very trivial problem yet I haven't found any solution that doesn't involves me going through the List and check if its contained before adding. Its an unnecessary extra step that I can't afford.

图像是一个自定义实现,并且确实实现了hashCode/equals,并且已经证明这不是问题.即使我从实体中删除,上述实验结果也不会改变.

Edit 1: Image is a custom implementation and does implements hashCode/equals and already proved its not the problem. Even if I remove from the entities the above experiments results doesn't change.

我调试了代码,并且在进行 lChapter.equals(psChapter); 时,如果您进入了 Objects.equals(distributors,chapter.distributors)Chapter的equals函数,将进入分配器equals函数,而在 psChapter.equals(lChapter); 上,它将进入PersistentSet一个.

Edit 2: I debugged the code and when doing lChapter.equals(psChapter); if you go into Objects.equals(distributors, chapter.distributors) of the Chapter's equals function, it goes to the Distributor equals function whereas on the psChapter.equals(lChapter); it goes into the PersistentSet one.

推荐答案

更新

经过休眠JIRA后,当急切加载时,PersistentSet不遵守哈希码/等于合约这是一个已知问题.

After going through the hibernate JIRA PersistentSet does not honor hashcode/equals contract when loaded eagerly it is a known issue.

在某些情况下急于加载的集合会在填充其字段值之前对其项目调用哈希码,从而影响其他方法如contain(),remove()等.

该修复程序计划用于6.0.0 Alpha.

The fix is planned for 6.0.0 Alpha.

根据JIRA中的一项建议作为解决方法,最好坚持使用LAZY系列.EAGER的获取不利于性能,可能会导致生成笛卡尔积,并且您无法对集合进行分页.

And as per one of the suggestions in the JIRA as a workaround, it's much better to stick to LAZY collections. EAGER fetching is bad for performance, can lead to Cartesian Products, and you can't paginate the collection.

那应该解释为什么

Chapter.equals(psChapter); 返回 true ,因为它使用普通的Set.equals

Chapter.equals(psChapter); returns true since it uses normal Set.equals

psChapter.equals(lChapter); 返回 false .

这通过PersistentSet而违反了哈希码/等号约定,因此即使元素存在于Set中,也不能保证返回true.此外,它还导致允许向Set中添加重复的元素.

This goes via PersistentSet while violates the hashcode/equals contract and thus it is not guaranteed to return true even if the element is present in the Set. And further it results in allowing adding duplicate elements to the Set as well.

这篇关于Hibernate的PersistentSet不使用hashCode/equals的自定义实现的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆