Search This Blog

Saturday 15 October 2011

Hibernate Collections - The whole variety -1

In the previous post we saw the varied collections available for use in Hibernate. I created a class which includes the different collection types.
public class Person {
    private Long id;
    private String name;    private Set<String> kids = new HashSet<String>();
    private List<String> degrees = new ArrayList<String>();
    private Map<String, Integer> degreeScore = new HashMap<String, Integer>();
    private Collection<String> chocolates = new ArrayList<String>();
    private SortedSet<String> hobbies = new TreeSet<String>();
    private SortedMap<String, Integer> kidsAge = new TreeMap<String, Integer>();
    public Long getId() {
        return id;
    }
    public void setId(Long id) {
        this.id = id;
    }
        //setter and getter methods 
}

The Person class here has:

  1. A collection of kids. (The names of kids are unique, the orders of their names is however not preserved -> Hence a Set)
  2. A collection of degrees. (These degree names need to be saved in the order of insertion.Duplicates are OK, e.g. a double Doctorate -> Hence a List)
  3. A collection of hobbies sorted by name. (The hobbies are unique for a person - Hence a SortedSet
  4. A collection of the scores in each degree. (As score needed for each degree earned by the person, a Map is used)
  5. A collection of chocolates.( Just a collection-> duplicates is fine, no sorting/ordering needed - Hence a Bag (explained later))
  6. A collection of the age of each kid,stored in descending order of name. (As age needed for each child of the person and the sort constraints, a SortedMap is used.)
The hibernate mapping document gives the remaining details
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.collection.basic">
    <class name="Person" table="PERSON">
        <id name="id" type="long">
            <column name="ID" />
            <generator class="identity" />
        </id>
        <property name="name" type="string">
            <column name="NAME" />
        </property>
        <set name="kids" table="PERSON_KIDS">
            <key column="PERSON_ID" /> <!-- This declares the Foreign Key column -->
            <element type="string" column="KID" not-null="true" />
            <!-- The Primary Key is a composite of both the columns -->
        </set>
        <list name="degrees" table="PERSON_DEGREES">
            <key column="PERSON_ID" /> <!-- Foreign Key -->
            <list-index column="DEGREE_INDEX" /> <!-- base ="0" -->
            <!-- Primary Key here is a composite of the list-index and the Foreign 
                Key -->
            <element type="string" column="DEGREE" not-null="true" />
        </list>
        <map name="degreeScore" table="PERSON_DEGREE_SCORE">
            <key column="PERSON_ID" /> <!-- Foreign Key -->
            <map-key column="DEGREE" type="string" />
            <!-- Primary Key here is a composite of the map-key and 
                 the Foreign Key -->
            <element type="integer" column="SCORE" not-null="true" />
        </map>
        <set name="hobbies" table="PERSON_HOBBIES" sort="natural">
            <!-- uses the compareTo method() -->
            <key column="PERSON_ID" /> <!-- Foreign Key -->
            <element type="string" column="HOBBY" not-null="true" />
        </set>
        <map name="kidsAge" table="PERSON_KID_AGE"
            sort="com.collection.comparator.StringReverseComparator"> 
            <!-- customized sorting -->
            <key column="PERSON_ID" /> <!-- Foreign Key -->
            <map-key column="KID" type="string" />
            <element type="integer" column="AGE" not-null="true" />
        </map>
        <idbag name="chocolates" table="PERSON_CHOCOLATES">
            <key column="PERSON_ID" />  <!-- Foreign Key -->
            <collection-id type="long" column="PERSON_CHOCOLATE_ID">
                <generator class="assigned" /> <!-- Primary Key-->
            </collection-id>
            <element type="string" column="CHOCOLATE" not-null="true" />     
        </idbag>  
    </class>
</hibernate-mapping>

Consider the <set>. 

  1. The mapping indicates that the set of kid's names are stored in a different table(PERSON_KIDS). 
  2. The <key> element indicates the foreign-key in the table(Id of Person) which is used to identify each persons kids. 
  3. The <element> element here indicates that the kids name is a simple value (or single column).
Next is the <list> element. 
  1. This is very much similar to the set element except for the <list-index> element. This field specifies the position of the degree in the list. (Remembered Lists unlike sets are ordered. The column helps hibernate ensure that the degrees occur in the same order always in the list for a given Person). 
  2. The <list-index> includes "base" attribute which gives the initial value of the index to be used(default=0). 
  3. As the list does not have unique values the list-index column forms a part of the Primary key here.
The <map> element is a combination of key-value pairs. 
  1. The primary key here is the foreign key (Id of person) and the map key (Degree Name).
  2. This key is represented by the <map-key> element.
Hibernate as discussed in the previous post supports sorted versions of the map and the set. The sorting is achieved by specifying a value for the "sort" attribute. A value of "natural" indicates that the elements will be sorted as per the compareTo() method (In our case this means that the hobbies will be sorted in ascending order of names). The other option is to specify a custom sort class which is done for the SortedMap above. The Simple Comparator is as below:
package com.collection.comparator;

import java.util.Comparator;

public class StringReverseComparator implements Comparator<String> {

    @Override
    public int compare(String o1, String o2) {        
        return o2.compareTo(o1);
    }

}
The last is the <idbag>element. 
  1. This is a collection that has no ordering (unlike a list) and allows duplicates(unlike a set).A real world example for the same would be a bag of fruits. 
  2. Unfortunately, the Java Collections Framework has no bag implementation. However the Collection Interface can be used to implement a bag. The bag of chocolates is represented as
    Collection<String> chocolates = new ArrayList<String>();
  3. Internally Hibernate will map the property with a PersistentBag class that can deal with Lists. As a result the ArrayList representing the chocolates is not guaranteed to return the chocolates in a fixed sequence.  
The next step is to execute the code.

No comments:

Post a Comment