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
中添加一个额外的方法来添加联系人。您可以在此处找到更多信息:
我有两个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
中添加一个额外的方法来添加联系人。您可以在此处找到更多信息: