Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/364.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/spring/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 冬眠';s PersistentSet未使用hashCode/equals的自定义实现_Java_Spring_Hibernate - Fatal编程技术网

Java 冬眠';s PersistentSet未使用hashCode/equals的自定义实现

Java 冬眠';s PersistentSet未使用hashCode/equals的自定义实现,java,spring,hibernate,Java,Spring,Hibernate,所以我有一本实体书 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 (t

所以我有一本实体书

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);
  }
}
我有一个新旧章节的
列表
,我只需要在书中添加新章节。 Hibernate使用其自定义实现
PersistentSet
获取并填充数据库中的所有章节

我试图解决的问题是只从列表中添加PersistentSet中不存在的章节。但是,对于这一点,由于Chapter不使用id字段来计算hashCode/equals,我可以将列表中的所有章节添加到PersistentSet,结果应该是一个集合,该集合将已经存在的章节从列表中排除,并包含不在集合中的章节。好。。。这并没有发生

Hibernate的
PersistentSet
没有使用我为
Distributor
实体定义的hashCode/equals函数,而是使用它的一些内部实现,导致列表和集合中的章节具有不同的hashCode,并且不相等。让我们调用列表
lChapter
中的一个章节和PersistentSet
psChapter
中的一个章节,并假设它们除了Id之外是相等的。 如果我这样做

但如果我这样做了

psChapter.equals(lChapter); //False
如果我这样做了

book.getChapters().addAll(chapters);
由于
书籍
是一个包含20章的附加实体,而
章节
列表包含21章,因此结果是一个包含41章的集合

我做错什么了?我发现这是一个非常小的问题,但我还没有找到任何解决方案,不涉及我检查列表,并检查它是否包含在添加之前。这是不必要的额外步骤,我负担不起

编辑1:Image是一个自定义实现,它实现了hashCode/equals,并且已经证明它不是问题所在。即使我从实体中移除,上述实验结果也不会改变


编辑2:我调试了代码,在执行
lChapter.equals(psChapter)时
如果进入章节的equals函数的
Objects.equals(distributors,chapter.distributors)
,它将进入Distributor equals函数,而在
psChapter.equals(lChapter)上它进入到PersistentSet中。

更新

在经历了hibernate JIRA之后,这是一个已知的问题

在某些情况下,急切加载的集合在填充其字段值之前对其项调用hashcode,从而影响其他方法,如contain()、remove()等

计划对6.0.0 Alpha进行修复

根据JIRA中的一条建议,作为一种解决方法,坚持使用惰性集合要好得多。即时抓取不利于性能,可能导致笛卡尔积,并且无法对集合进行分页

这应该可以解释为什么

Chapter.equals(psChapter)
返回
true
,因为它使用normal Set.equals

psChapter.equals(lChapter)返回
false


这通过PersistentSet进行,同时违反hashcode/equals约定,因此即使元素存在于集合中,也不能保证返回true。此外,它还允许向集合中添加重复的元素。

我用main方法尝试了您的代码,它按预期工作,如下所示

你能试试你的密码吗

public static void main(String[] args) {

    LocalDate now = LocalDate.now();

    Distributor db = new Distributor();
    db.setId("1");
    db.setLogoImage(null);
    db.setName("Name");
    Set<Distributor> dbs = new HashSet<>();
    dbs.add(db);

    Chapter c= new Chapter();
    c.setDistributors(dbs);
    c.setId("1");
    c.setNumber("123");
    c.setReleaseDate(now);
    c.setTitle("10:30");
    Set<Chapter> chapters = new HashSet<>();
    chapters.add(c);


    Book b= new Book();
    b.setChapters(chapters);
    b.setCoverImage(null);
    b.setDescription("Description");
    b.setId("1");
    b.setName("Name");


    Set<Distributor> dbs1 = new HashSet<>();
    Distributor db1 = new Distributor();
    db1.setId("1");
    db1.setLogoImage(null);
    db1.setName("Name");
    dbs1.add(db1);

    Chapter c1 = new Chapter();
    c1.setDistributors(dbs1);
    c1.setId("1");
    c1.setNumber("123");
    c1.setReleaseDate(now);
    c1.setTitle("10:30");

    System.out.println(chapters.add(c1));
    System.out.println(chapters.size());

}
publicstaticvoidmain(字符串[]args){
LocalDate now=LocalDate.now();
分发服务器db=新分发服务器();
db.setId(“1”);
db.setLogoImage(空);
db.setName(“名称”);
Set dbs=new HashSet();
添加(db);
第c章=新的一章();
c、 SET分销商(dbs);
c、 setId(“1”);
c、 设定编号(“123”);
c、 设置发布日期(现在);
c、 片名(“10:30”);
Set chapters=newhashset();
增加(c)章;
书b=新书();
b、 第三章(章);
b、 setCoverImage(空);
b、 设定说明(“说明”);
b、 setId(“1”);
b、 设置名称(“名称”);
Set dbs1=新的HashSet();
分发服务器db1=新分发服务器();
db1.setId(“1”);
db1.setLogoImage(空);
db1.集合名(“名称”);
dbs1.add(db1);
第c1章=新的一章();
c1.SET分销商(dbs1);
c1.setId(“1”);
c1.设定编号(“123”);
c1.设置发布日期(现在);
c1.片名(“10:30”);
系统输出打印LN(章节添加(c1));
System.out.println(chapters.size());
}

此问题的解决方法是在书籍章节之间的关系中添加一个
@OrderColumn
,如下所示:

public class Book {
  private String id;
  private String name;
  private String description;
  private Image coverImage;
  @OrderColumn
  private Set<Chapter> chapters;
...
}
公共课堂教材{
私有字符串id;
私有字符串名称;
私有字符串描述;
私人影像;
@订单列
专用章节;
...
}
这将去掉
PersistentSet
,而是使用Hibernate的
PersistentSortedSet
,它不会违反equals/hashCode契约


顺便问一下,我想知道为什么您没有任何
@OneToMany
/
@manytomy
注释?似乎Hibernate会自动完成(我觉得很恐怖)。Hibernate是如何决定这是一对多还是多对多关系的?

这些新章节有相同的分发对象吗?是的,它们完全相同。正如我所说,唯一的区别是Id字段。编辑帖子以包含相关信息。
lChapter
psChapter
分别是
章节
列表
集合
的实例吗?都是章节,都是相等的。psChapter从hibernate填充,lChapter从列表中获取。列表和集合包含的章节基本相同。就像我上面的例子。如果说列表有21章,21章中的20章已经在数据库中,但1章在列表中,两者都不是附加实体。另一方面,该集合有20个章节(与列表中的20个章节相同,但这是PersistentSet中的附加实体)。如果
book.getChapters().addAll(chapters);
public static void main(String[] args) {

    LocalDate now = LocalDate.now();

    Distributor db = new Distributor();
    db.setId("1");
    db.setLogoImage(null);
    db.setName("Name");
    Set<Distributor> dbs = new HashSet<>();
    dbs.add(db);

    Chapter c= new Chapter();
    c.setDistributors(dbs);
    c.setId("1");
    c.setNumber("123");
    c.setReleaseDate(now);
    c.setTitle("10:30");
    Set<Chapter> chapters = new HashSet<>();
    chapters.add(c);


    Book b= new Book();
    b.setChapters(chapters);
    b.setCoverImage(null);
    b.setDescription("Description");
    b.setId("1");
    b.setName("Name");


    Set<Distributor> dbs1 = new HashSet<>();
    Distributor db1 = new Distributor();
    db1.setId("1");
    db1.setLogoImage(null);
    db1.setName("Name");
    dbs1.add(db1);

    Chapter c1 = new Chapter();
    c1.setDistributors(dbs1);
    c1.setId("1");
    c1.setNumber("123");
    c1.setReleaseDate(now);
    c1.setTitle("10:30");

    System.out.println(chapters.add(c1));
    System.out.println(chapters.size());

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