In this case we allow navigation in both directions between the two classes. On the Many side it is a standard java reference. on the One side it is a collection. However, the two associations are not independent of each other but rather, one is the inverse of the other and the same foreign key column is used for both associations. Thus our
To achieve this, we start by using the
Thus the mapping file for
The mapping file for student is as follows:
Now all the programmer has to do is to ensure that, when the Lecturer's advisee property property is changed, the corresponding correct changes are made to the appropriate Student's advisor property. So long as both are done together, the Java object graph will be correct and the correct update on disk will be made as well. Furthermore, since the association belongs to the Student, there will never be an insert of a Student record with a null Lecturer foreign key if the Student has an advisor, thus avoiding not-null constraint breaking. To ensure that these updates are made together, it is usual to add some convenience methods: in Lecturer, change the getAdvisees() and setAdvisees() methods to private and add a convenience method to update the object graph correctly when adding a new Student advisee to a Lecturer:
Note how we are careful to correctly handle removal of a
If we have a true composition relationship, i.e., a parent-child relationship where if the parent gets deleted then the child should also be deleted etc., then we should change the
Lecturer
object now has a property which is a collection of Student
objects while the Student
objects have a properties which refers to the Student
's supervising Lecturer
.To achieve this, we start by using the
many-to-one
element as before in the mapping file for the Student
class, and the Set
element as before in the mapping file for the Lecturer
class, ensuring that both associations use the same column in Student
's table to encode the association. Then we add a new attribute, inverse="true"
to the set
element in Lecturer
's mapping file. Without this, adding a new Student
as an advisee to a Lecturer
would trigger Hibernate to set the foreign key column of the Student
table twice: once for each association that has been changed. The inverse
attribute tells hibernate that Student
owns the association and that Hibernate should not trigger updates of the foreign key column when it changes on the Lecturer
side. Thus the mapping file for
Lecturer
looks like this:<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN" "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd"> <hibernate-mapping> <class name="Lecturer" table="lecturers"> <id name="id" column="lecturer_id"> <generator class="sequence"/> </id> <version name="version" column="version"/> <property name="name" column="name"/> <set name="advisees" inverse="true" cascade="save-update" lazy="true"> <key column="lecturer_id"/> <one-to-many class="Student"/> </set> </class> </hibernate-mapping>
The mapping file for student is as follows:
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN" "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd"> <hibernate-mapping> <class name="Student" table="students"> <id name="id" column="student_id"> <generator class="sequence"/> </id> <version name="version" column="version"/> <property name="name" column="name"/> <property name="regNo" column="reg_no"/> <many-to-one name="advisor" column="lecturer_id" cascade="save-update"/> </class> </hibernate-mapping>
Now all the programmer has to do is to ensure that, when the Lecturer's advisee property property is changed, the corresponding correct changes are made to the appropriate Student's advisor property. So long as both are done together, the Java object graph will be correct and the correct update on disk will be made as well. Furthermore, since the association belongs to the Student, there will never be an insert of a Student record with a null Lecturer foreign key if the Student has an advisor, thus avoiding not-null constraint breaking. To ensure that these updates are made together, it is usual to add some convenience methods: in Lecturer, change the getAdvisees() and setAdvisees() methods to private and add a convenience method to update the object graph correctly when adding a new Student advisee to a Lecturer:
public void addAdvisee(Student st) { Lecturer oldAdvisor = st.getAdvisor() ; if (oldAdvisor != this) { if (oldAdvisor != null) oldAdvisor.getAdvisees().remove(st) ; st.setAdvisor(this); advisees.add(st) ; } }
Note how we are careful to correctly handle removal of a
Student
from a previous advising Lecturer
before adding it to this one. Whether you need to do something similar for your code will depend on your detailed design. If we have a true composition relationship, i.e., a parent-child relationship where if the parent gets deleted then the child should also be deleted etc., then we should change the
cascade
attribute on the set
element in the Lect
urer
mapping file to be all-delete-orphan
.
No comments:
Post a Comment