Reputation: 6637
I have two tables
Table Student Columns (Rollnumber, ....)
Table Phone Columns (STUD_ID,ID, phonetype, number)
Student class is
@Entity
@Table
public class Student {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
int rollNumber;
@OneToMany
Set<Phone> contacts;
:
: // Getter setters
}
Phone class is
@Entity
public class Phone {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
int id;
@Column
String type;
@Column
String number;
:
: // Getter setters
}
But this is not working
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);
But this does not create record in "Phone" table. In Phone class I do not need Student object. What extra configuration needed.
Partial solution
Finally I was able to do it. By using "Cascade" and "joincolumn" as follows.
@OneToMany(cascade=CascadeType.ALL)
@JoinColumn(name="STUD_ID")
public Set<Phone> getContacts() {
return contacts;
}
Queries are fired as follows ( as expected)
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=?
But as seen above it fires query "update Phone set STUD_ID=null where STUD_ID=?". What should I do so that it will fire Delete queries? Using
@OneToMany(cascade=CascadeType.ALL, orphanRemoval=true)
throw exceptions
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
Solution
@OneToMany(cascade=CascadeType.ALL, orphanRemoval=true)
@JoinColumn(name="STUD_ID")
public Set<Phone> getContacts() {
return contacts;
}
As mentioned by accepted solution changed the code.
s1.getContacts().clear();
Phone p1 = new Phone();
s1.getContacts().add(p1);
Phone p2 = new Phone();
s1.getContacts().add(p2);
Delete queries were fired as well. All queries were
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=?
Upvotes: 0
Views: 76
Reputation: 19976
The reason of the error
A collection with cascade="all-delete-orphan" was no longer referenced ...
is that Hibernate tracks a collection with orphanRemoval=true
using a proxy.
So you really have a proxy in your persistent class (when you get a Student
from a database using session.get(Student.class, 24)
):
@Entity
@Table
public class Student {
@OneToMany
HibernateProxySet<Phone> contacts;
}
If you do this
s1.setContacts(phoneSet);
You, obviously, override HibernateProxySet
by your HashSet
. Hibernate generates HibernateException
in this situation, because of it wants to track all changes to the contacts
using HibernateProxySet.
How to solve
@Entity
@Table
public class Student {
@OneToMany
Set<Phone> contacts = new HashSet<>();
}
s1.getContacts().clear();
s1.getContacts().add(p1);
s1.getContacts().add(p2);
I have added a contacts
field initialization by new HashSet<>()
. It is not mandatory, of course, just for convenience. You can think about using such strategy in every persistent class.
Also you can consider to add an additional method to Student
to add contacts. You can find additional information here:
Upvotes: 1