Search This Blog

Sunday, 30 October 2011

Component of Components

Hibernate allows us to compose our components out of other components. This is making extreme use of java in the SQL world, but provides us with a great deal of flexibility. I modified the address class in the previous example to be composed of components.
So the address class now looks like
public class Address {
    private Person person;
    private String city;
    private Location location;
    private ZipCode zipCode;
        //setter-getters 
}
The components placed inside Address class are as follows:

public class Location {
    private Street street;
        //setter-getters
}
public class Street {
    private String name;
        //setter-getters
}
public class ZipCode {
    private String zipCode;
        //setter-getters
}
The database table is unchanged.However the mapping file is modified to the following:

<?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.model.components.bidirectional">
    <class name="Person" table="PERSON">
        <id name="id" type="long">
            <column name="ID" />
            <generator class="native" />
        </id>
        <property name="name" type="string">
            <column name="NAME" />
        </property>

        <component name="address" class="ComponentAddress">
            <parent name="person" />
            
            <property name="city" type="string" not-null="true">
                <column name="CITY" />
            </property>
            <component name="location" class="Location">
                <component name="street" class="Street">
                    <parent name="person" /> 
                    <property name="name" type="string" not-null="true">
                        <column name="STREET" />
                    </property>
                </component>
            </component>
            
            <component name="zipCode" class="ZipCode">    
                <property name="zipCode" type="string" not-null="true">
                    <column name="ZIP_CODE" />
                </property>
            </component>
        </component>
    </class>
</hibernate-mapping>
I have highlighted the component nesting levels in the code above. As can be seen the back-link is not only present for the outer-most component but also for inner component Location. Backlinks always refer to the entity and not the class that includes the component instance !!
I decided to execute an HQL query to retrieve a Person object for a given Street name

static void testHqlRetrieval() {
    Session session = SESSION_FACTORY.openSession();
    try {
        //get Entity with query on component
        Query query = session.createQuery("from Person p where p.address.location.street.name = ?");
        query.setString(0, "Aundh Road");
        Person person = (Person) query.list().get(0);
        System.out.println("Person : " + person + " City : " 
              + person.getAddress().getCity());
        System.out.println("Inner person back -reference " 
              + person.getAddress().getLocation().getStreet().getPerson().getName());
    } catch (HibernateException e) {
        e.printStackTrace();
    } finally {
        session.close();
    }
}
The code for back-reference is crooked to say the least, but it works ;P The logs indicate the SQL query fired

3016 [main] DEBUG org.hibernate.SQL  -  
    select
        person0_.ID as ID0_,
        person0_.NAME as NAME0_,
        person0_.CITY as CITY0_,
        person0_.STREET as STREET0_,
        person0_.ZIP_CODE as ZIP5_0_ 
    from
        PERSON person0_ 
    where
        person0_.STREET=?

No comments:

Post a Comment