Hibernate Relationship Mapping
Hibernate relationship mapping takes care of mapping the relationship in the relational world. The relationship that exist in the relational world are:- @OneToOne
- @OneToMany
- @ManyToOne
- @ManyToMany
One To One
Let's say we have Address and Student in its own table and we expose Address also as an entity.
@Entity public class AddressEntity implements Serializable{ protected Long id; …. @Id @GeneratedValue @Column(name="ADDRESS_ID") public Long getId() { return id; }
Map the relationship in the Student entity with directionality build from Student side
In Student class
... private AddressEntity address; //Cascade Type defines that if the owning entity in this case Student is saved, than //whether the AddressEntity will also get saved. @OneToOne(cascade={CascadeType.ALL}) @JoinColumn(name="ADDRESS_ID") public AddressEntity getAddressEntity() { return address; } ...
Also note the cascade type here. The cascade type defines whether the AddressEntity will get saved when we save Student. For example let's say the mapping in Student class, if we remove the Cascade type will be:
... private AddressEntity address; @OneToOne // comment out - (cascade={CascadeType.ALL}) @JoinColumn(name="ADDRESS_ID") public AddressEntity getAddressEntity() { return address; } ...
Now let's try to save a Student and AddressEntity
Student student = new Student(); AddressEntity add = new AddressEntity(); student.setAddressEntity(add); //If you try to save student, it will throw an exception as //it finds AddressEntity wired to it but AddressEntity is transient. //To persist the transient AddressEntity with the Student uncomment the CascadeType //session.save(student);
We can make the primary key for both the related table same. It means that in the Address table the primary key and foreign key are same.
In the Student class
@OneToOne(cascade={CascadeType.ALL}) @PrimaryKeyJoinColumn public AddressEntity getAddressEntity() { return addressEntity; }
In the above case the AddressEntity can be reached from Student but from AddressEntity you cannot reach to Student. Map the Student entity in the AddressEntity class
... protected Student student; @OneToOne(mappedBy="bankAccount") public Student getStudent() { return student; } ...
Note that this relationship in the Java world does not makes any change to the relational world.
In the case of bidirectional association, there is a notion of owning entity. The owning entity governs in what case the relationship will materialized in the database.The owning entity is the entity which is on the opposite or inverse side of mappedBy. In the case as the mappedBy is on the AddressEntity, the Student entity becomes the owning type. Now look at following piece of code
Student student = new Student(); AddressEntity add = new AddressEntity(); //Map the relationship from AddressEntity side add.setStudent(student); //we will assume that CascadeType is All. session.save(student);
If we look into the database, the Student and AddressEntity both are created in the database but the relationship is not build between Student and AddressEntity table. To fix the problem change the above code to
Student student = new Student(); AddressEntity add = new AddressEntity(); //Map the relationship from Student side student.setAddressEntity(add); //we will assume that CascadeType is All. session.save(student);
Now the relationship will be properly created as we have made the relationship from owning side. It's a good price to build the relationship from both side whenever the relationship is effected from one side.
Student student = new Student(); AddressEntity add = new AddressEntity(); //Good Practice: Map the relationship on both side student.setAddressEntity(add); add.setStudent(student); //we will assume that CascadeType is All. session.save(student);
For more discussion on concept of owning entities see here.
For owning entity, you have to take care of following:
- If a AddressEntity has to be assigned to a different student, than unset the addressEntity on the original student and set it into the new student.
- For deleting a AddressEntity, unset it from the student object and than remove it from database calling remove method on entity manager.
One To Many
Let's have PhoneEntity table with one to Many relationship from Student.
Student Table
STUDENT_ID //Primary Key ...
PhoneEntity table
PHONE_ID //Primary Key STUDENT_ID //Foreign Key ...
Now the PhoneEntity class looks like
@Entity public class PhoneEntity implements Serializable{ protected int id; protected String number; @Id @GeneratedValue @Column(name="PHONE_ID") public int getId() {
There is no reference to Student in PhoneEntity class, though the relationship is maintained in PhoneEntity table in database. Now to build the One to Many relationship in Student
@OneToMany(cascade={CascadeType.ALL}) public Collection<PhoneEntity> getPhoneEntityList() { return phoneEntityList; }
To save phone Entity the code would look like
Collection<PhoneEntity> phoneList = new ArrayList<PhoneEntity>(); PhoneEntity p1 = new PhoneEntity(); p1.setNumber("100"); phoneList.add(p1); PhoneEntity p2 = new PhoneEntity(); p2.setNumber("200"); phoneList.add(p2); student.setPhoneEntityList(phoneList);
We can tell hibernate that if an element is removed from a collection than delete it from database as this is the only reference to that entity.
@OneToMany(cascade={CascadeType.ALL}) @org.hibernate.annotations.Cascade(value=org.hibernate.annotations.CascadeType.DELETE_ORPHAN ) public Collection<PhoneEntity> getPhoneEntityList() { return phoneEntityList; }
If we want the relationship data to be managed in a join table
@OneToMany(cascade={CascadeType.ALL}) @JoinTable(name="STUDENT_PHONE",joinColumns={@JoinColumn(name="STUDENT_ID")}, inverseJoinColumns={@JoinColumn(name="PHONE_ID")}) public Collection<PhoneEntity> getPhoneEntityList() { return phoneEntityList; }
Now let's see Many To One unidirectional relationship. Let's say we have a country table and Student is mapped to Country with Many to One relationship.
Student Table
STUDENT_ID //Primary Key COUNTRY_ID //foreign Key ...
Country Table
COUNTRY_ID //Primary Key ...
Country Entity
@Entity public class Country implements Serializable{ protected long id; protected String name; @Id @GeneratedValue @Column(name="COUNTRY_ID") public long getId() { return id; } ...
Student Entity
private Country country; @ManyToOne @JoinColumn(name="COUNTRY_ID") public Country getCountry() { return country; }
Note that we are not using cascade here as normally the country is a master data and should not be created or deleted in the context of a Student. To save a Student
Country country = new Country(); country.setName("India"); session.save(country); student.setCountry(country);
Many to one and One to many are two sides of the same relationship. Let’s convert Student and Country into bidirectional relationship.
//the owning side of relationship is Many To One @OneToMany(mappedBy="country") public Collection<Student> getStudentList() { return studentList; }
For persistence to work we have to call student.setCountry. If we just call country.getStudentList().add(student), The relationship will not change in the database. As a good practice Always wire both side of relationship.
Many To Many
ManyToMany relationship happens when both side maintains collection based relationship.Let’s take an example of Student and Language they speak. A student can speak many language. Similarly a language can be spoken by many students
Language Entity bean
@Entity public class Language implements Serializable{ protected long id; protected String name;
Student Bean
@ManyToMany @JoinTable(name=“A_B",joinColumns={@JoinColumn(name=“C")}, inverseJoinColumns={@JoinColumn(name=“D")}) public Collection<Language> getLanguageList() { return languageList; }
For Many to Many bidirectional
Language Bean
@ManyToMany(mappedBy="languageList") public Collection<Student> getStudentList() { return studentList; }
For modifying the same ownership rule applies as we have seen in other bidirectional relationships.
The collection can be fetched in certain order. E.g if we want to fetch the list of languages in certain order we can say on the Student side of relationship
@ManyToMany @OrderBy(“name ASC”) @JoinTable(name="STUDENT_LANGUAGE", joinColumns={@JoinColumn(name="STUDENT_ID")}, inverseJoinColumns={@JoinColumn(name="LANGUAGE_ID")}) public List<Language> getLanguageList() { return languageList; }
For descending order use name=DESC
Back to Hibernate Index
Back To Java Home
Back To Home
Sidebar
Last wiki comments
- AOP: Thanks
- Lalit Bhatt: Superb Collection
- Lalit Bhatt: J2EE training
- Introduction to ORM: timberland shoes
- Introduction to ORM: jordan shoes
- Introduction to ORM: nike air max
- Pune Tourist Spots: KONARK PARK CLOSED
- jQuery Form Validations: Jquery Developer
- Spring Introduction: RG
- SOAP: Re: Assertion
Sidebar
Random Pages
- Comprehensive Overview of Java Technologies
- SOAP
- Pune Hill Forts For Trekking
- Windows Antivirus
- Source Code Control Systems
- JavaFX Data Binding and Trigger
- Introduction to Seam
- CSS - Handling Browser Moods
- Parsers Introduction
- Spring Annotation driven Aspects
- JAXB Validation using Schema
- Spring POJO Aspects
- What markets work on?
- Why projects fail?
- Bharat Band - Jai ho
- The concept of Nation
- Don't hide complexity if it cannot be handled in a robustway
Last blog post comments
-
Bharat Band - Jai ho: How do we protest?
Wed 18 of Aug., 2010 13:13 IST
-
Divided by Destiny: Contact
Fri 23 of July, 2010 16:02 IST
-
Future of Java: thesis writing
Sat 17 of July, 2010 01:50 IST
-
Hang till Death Mr. Kasab: some change
Mon 28 of June, 2010 16:03 IST
-
God Religion : Why we are confused?: Re: Is GOD Necessary?
Tue 15 of June, 2010 17:29 IST
-
God Religion : Why we are confused?: Is GOD Necessary?
Tue 15 of June, 2010 13:06 IST
-
The reason in religion: good
Wed 10 of Mar., 2010 18:30 IST
-
The confusion of Design Patterns: I think at macro level you are right...
Tue 23 of Feb., 2010 03:31 IST
-
The Indian Municipality: Comment
Fri 22 of Jan., 2010 13:20 IST
-
What Government should do?: Re: Review of the Indian Law and Order and Justice Dispensation regime.
Fri 22 of Jan., 2010 13:16 IST
Post new comment