Hibernate OneToMany 配置。需要帮助

Hibernate OneToMany configuration. Help needed

我有两个table

Table Student  Columns (Rollnumber, ....)
Table Phone    Columns (STUD_ID,ID, phonetype, number)

学生class是

@Entity
@Table
public class Student {
  @Id
  @GeneratedValue(strategy=GenerationType.AUTO)
  int rollNumber;

  @OneToMany
  Set<Phone> contacts;
  :
  : // Getter setters
}

Phone class 是

@Entity
public class Phone {

  @Id
  @GeneratedValue(strategy=GenerationType.AUTO)
  int id;
  @Column
  String type;
  @Column
  String number;
:
: // Getter setters

}

但这不起作用

        Student s1 = session.get(Student.class, 24);

        Phone p1 = new Phone();
        p1.setNumber("1111111");
        p1.setType("Ghar");


        Phone p2 = new Phone();
        p2.setNumber("222222");
        p2.setType("Office");


        Set<Phone> phoneSet = new HashSet<>();
        phoneSet.add(p1);
        phoneSet.add(p2);

        s1.setContacts(phoneSet);

        session.save(s1);

但这不会在 "Phone" table 中创建记录。在 Phone class 我不需要 Student 对象。 需要什么额外的配置。

部分解

我终于做到了。通过使用 "Cascade" 和 "joincolumn" 如下。

@OneToMany(cascade=CascadeType.ALL)
@JoinColumn(name="STUD_ID")
public Set<Phone> getContacts() {
    return contacts;
}

查询如下触发(如预期)

Hibernate: select student0_.rollNumber as rollNumb1_3_0_, student0_.ADDR_ID as ADDR_ID4_3_0_, student0_.CLASS_TEACHER_ID as CLASS_TE5_3_0_, student0_.name as name2_3_0_, student0_.surname as surname3_3_0_, address1_.ID as ID1_0_1_, address1_.Country as Country2_0_1_, address1_.details as details3_0_1_, teacher2_.teacherId as teacherI1_4_2_, teacher2_.name as name2_4_2_, teacher2_.surname as surname3_4_2_ from Student student0_ left outer join ADDRESS address1_ on student0_.ADDR_ID=address1_.ID left outer join Teacher teacher2_ on student0_.CLASS_TEACHER_ID=teacher2_.teacherId where student0_.rollNumber=?
Hibernate: call next value for hibernate_sequence
Hibernate: call next value for hibernate_sequence
Hibernate: insert into Phone (number, stud_id, type, id) values (?, ?, ?, ?)
Hibernate: insert into Phone (number, stud_id, type, id) values (?, ?, ?, ?)
Hibernate: update Phone set STUD_ID=null where STUD_ID=?
Hibernate: update Phone set STUD_ID=? where id=?
Hibernate: update Phone set STUD_ID=? where id=?

但如上所示,它会触发查询 "update Phone set STUD_ID=null where STUD_ID=?"。我应该怎么做才能触发删除查询? 使用

@OneToMany(cascade=CascadeType.ALL, orphanRemoval=true)

抛出异常

Caused by: org.hibernate.HibernateException: A collection with cascade="all-delete-orphan" was no longer referenced by the owning entity instance: com.kaushik.winnersoft.data.Student.contacts

解决方案

@OneToMany(cascade=CascadeType.ALL, orphanRemoval=true)
@JoinColumn(name="STUD_ID")
public Set<Phone> getContacts() {
    return contacts;
}

如已接受的解决方案所述,已更改代码。

s1.getContacts().clear();
Phone p1 = new Phone();
s1.getContacts().add(p1); 
Phone p2 = new Phone();
s1.getContacts().add(p2);

删除查询也被触发。所有查询都是

Hibernate: select student0_.rollNumber as rollNumb1_3_0_, student0_.ADDR_ID as ADDR_ID4_3_0_, student0_.CLASS_TEACHER_ID as CLASS_TE5_3_0_, student0_.name as name2_3_0_, student0_.surname as surname3_3_0_, address1_.ID as ID1_0_1_, address1_.Country as Country2_0_1_, address1_.details as details3_0_1_, teacher2_.teacherId as teacherI1_4_2_, teacher2_.name as name2_4_2_, teacher2_.surname as surname3_4_2_ from Student student0_ left outer join ADDRESS address1_ on student0_.ADDR_ID=address1_.ID left outer join Teacher teacher2_ on student0_.CLASS_TEACHER_ID=teacher2_.teacherId where student0_.rollNumber=?
Hibernate: select contacts0_.STUD_ID as STUD_ID3_2_0_, contacts0_.id as id1_2_0_, contacts0_.id as id1_2_1_, contacts0_.number as number2_2_1_, contacts0_.stud_id as stud_id3_2_1_, contacts0_.type as type4_2_1_ from Phone contacts0_ where contacts0_.STUD_ID=?
Hibernate: call next value for hibernate_sequence
Hibernate: call next value for hibernate_sequence
Hibernate: insert into Phone (number, stud_id, type, id) values (?, ?, ?, ?)
Hibernate: insert into Phone (number, stud_id, type, id) values (?, ?, ?, ?)
Hibernate: update Phone set STUD_ID=null where STUD_ID=? and id=?
Hibernate: update Phone set STUD_ID=null where STUD_ID=? and id=?
Hibernate: update Phone set STUD_ID=? where id=?
Hibernate: update Phone set STUD_ID=? where id=?
Hibernate: delete from Phone where id=?
Hibernate: delete from Phone where id=?

错误原因

A collection with cascade="all-delete-orphan" was no longer referenced ...

是 Hibernate 使用代理跟踪 orphanRemoval=true 的集合。

所以你的持久化 class 中确实有一个代理(当你使用 session.get(Student.class, 24) 从数据库中获取 Student 时):

@Entity
@Table
public class Student {

  @OneToMany
  HibernateProxySet<Phone> contacts;

}

如果你这样做

s1.setContacts(phoneSet);

显然,您用 HashSet 覆盖了 HibernateProxySet。 Hibernate 在这种情况下生成 HibernateException,因为它想使用 HibernateProxySet 跟踪对 contacts 的所有更改。

如何解决

@Entity
@Table
public class Student {

  @OneToMany
  Set<Phone> contacts = new HashSet<>();

}

s1.getContacts().clear();
s1.getContacts().add(p1);
s1.getContacts().add(p2);

我通过 new HashSet<>() 添加了 contacts 字段初始化。当然,这不是强制性的,只是为了方便。你可以考虑在每个持久化 class.

中使用这样的策略

您还可以考虑在 Student 中添加一个额外的方法来添加联系人。您可以在此处找到更多信息:

Hibernate - 具有 cascade=”all-delete-orphan” 的集合不再被拥有的实体实例引用