Monday, July 28, 2014

Collection Mapping In Hibernate

Hibernate supports collection mapping as value type. In Hibernate collection mapping, the collection are mapped into a separate table but are not exposed as entity on the Java side. Hibernate supports following collection interfaces as value type:
  • java.util.Set – java.util.HashSet is used to store value.
  • java.util.SortedSet – java.util.TreeSet is used to store value.
  • java.util.List – java.util.ArrayList is used to store value. Preserves the position with an index column
  • Bag semantics – java.util.ArrayList is used to store valre however the position is not preserved.
  • java.util.Map – java.util.HashMap is used to store value.
  • java.util.SortedMap – java.util.TreeMap is used to store value.
Let’s say we want to store Phones for a Student. There are more than one Phone for a Student. So we will have two tables corresponding to Student and Phone. However we do not want to expose Phone
Table STUDENT
STUDENT_ID

...

Table PHONE
STUDENT_ID

NUMBER

...

STUDENT_ID is the foreign key and PHONE table has no primary key. To map the Phone collection as a Set in the Student Entity class
Student class
...

@org.hibernate.annotations.CollectionOfElements(targetElement = java.lang.String.class)

@JoinTable( name="PHONE",joinColumns = @JoinColumn(name="STUDENT_ID"))

@Column(name="PHONE_NO")

public Set<String> getPhones() {
...

The lifecycle of Phone is tightly coupled to Student. Also Phone table is not exposed as an entity. If the Set need to be sorted
...

@org.hibernate.annotations.CollectionOfElements(targetElement = java.lang.String.class)

@JoinTable( name="PHONE",joinColumns = @JoinColumn(name="STUDENT_ID"))

@Column(name="PHONE_NO")

@org.hibernate.annotations.Sort(type=org.hibernate.annotations.SortType.NATURAL)
public Set<String> getPhones() {
...

A comparator can also be used for Sort type.
To map the Phone collection as a list
...

@org.hibernate.annotations.CollectionOfElements

@JoinTable( name="PHONE",joinColumns = @JoinColumn(name="STUDENT_ID"))

@org.hibernate.annotations.IndexColumn(name=“INDEX_POSITION", base =1)

@Column(name="PHONE_NO")
public List<String> getPhones() {
    return phones;
}
---

Here the index is mapped to a INDEX_POSITION column in the table and preserves the ordering. If the index is not given, this works like a Bag. Bag is a list but does not preserves the position.
To map Phone as a map where PHONE_NAME will act as key and PHONE_NO as value from the PHONE table. To map it
...

@org.hibernate.annotations.CollectionOfElements

@JoinTable( name="PHONE",joinColumns = @JoinColumn(name="STUDENT_ID"))

@org.hibernate.annotations.MapKey(columns = @Column(name="PHONE_NAME"))

@Column(name="PHONE_NO")
public Map<String,String> getPhones() {
...

Here the Phone table is mapped directly as a collection. We can also expose Phone as a value object. In this case define Phone as a class
@Embeddable

public class PhoneValue {

    

  protected Student student;

  protected String name;
  protected String phoneNumber;
    
  @org.hibernate.annotations.Parent
  public Student getStudent() {
    return student;
 }
 ...

Also in the above case we maintain a back pointer for Student so that we can navigate from Phone to Student. To define the collection of embedded object in Student class
...

protected Collection<PhoneValue> phoneValues = new ArrayList<PhoneValue>();

@org.hibernate.annotations.CollectionOfElements

@JoinTable(name = "Student_Phone_Value",joinColumns = @JoinColumn(name="STUDENT_ID"))

@CollectionId(columns= @Column(name="STUDENT_PHONE_VALUE_ID"),    

                               type=@org.hibernate.annotations.Type(type="long"),

                       generator="sequence")
public Collection<PhoneValue> getPhoneValues() {
       return phoneValues;
}
...    

Hibernate collection mapping is a way of mapping the collection table as values. The lifecycle of the the collections are tightly bound to the collection of the owning entity.

More write-ups on Hibernate

No comments:

Post a Comment