Wednesday 22 October 2014

Hibernate Tutorial

Preface

Writing a program that connects to an RDMS database was always a hard task to do. A major issue had always been the effort taken to represent the data as constructs on the application programming language. Hibernate provides you a simple way to map objects in the database as objects in the programming language, and supports many services needed by the API for Database interactions, such as:


Guiding Example


I think that learning from a guiding example is a best practice, because it spices up the dry reference stuff. I present here an example of managing Events and Persons participating in an event.




Overview


Hibernate Entities

A Hibernate entity is an instance of a class that represents persistent data on a storage device. The class is mapped to a database with one of Hibernate's supported mapping strategies (See "supported mapping strategies"). Like in a relational database each entity class has a name that describes the data it holds and a unique identifier is given to each of the class instances, that identifies the specific instance and the data it holds.

A Hibernate entity consists of:
  • A simple POJO class
  • A mapping strategy (aka. chosen implementation; See "supported mapping strategies")
  • Hibernate APIs.




Supported Entity Mapping Strategies

Hibernate supports several implementations to map POJO classes to a storage, and thus define the Object-Relational-Mappings (ORM):
  • XML Entity mappings using Hibernate APIs and "hbm.xml" files
  • Annotation Entity Mappings and Hibernate APIs
  • Java Persistence API (JPA)
  • Envers - From Hibernate 3.5, Envers is included as a Hibernate core module.
  • OSGi
Some implementations map a POJO class by doing minor modifications to it, (like in the case of JPA and Annotation mapping), while other implementations declare mapping associations elsewhere (like in the case of XML entity mappings through "hbm.xml" files.




Session Factory

Hibernate is using a single API to manage the persistence of its entities, no matter which database you are using or the means to connect to it. In Hibernate language it is called a Session Factory. The session factory takes under account various settings, such as which database to use, what are the connection settings, how to use the caching mechanism, which JDBC driver to use, etcetera. Hibernate uses the session factory for all entity operations (CRUD).



Configuring the Session Factory


The SessionFactory is a global Hibernate factory that is responsible for persisting and managing Hibernate Entities with a particular database. To configure it we use a SessionFactory configuration file - "hibernate.cfg.xml"




The Session Factory XML File


<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
      "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
      "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">

<hibernate-configuration>
  <session-factory>
    <!-- Database connection settings -->
    <property name="connection.driver_class">org.hsqldb.jdbcDriver</property>
    <property name="connection.url">jdbc:hsqldb:hsql://localhost</property>
    <property name="connection.username">sa</property>
    <property name="connection.password"></property>

    <!-- JDBC connection pool (use the built-in) -->
    <property name="connection.pool_size">1</property>

    <!-- SQL dialect -->
    <property name="dialect">org.hibernate.dialect.HSQLDialect</property>

    <!-- Enable Hibernate's automatic session context management -->
    <property name="current_session_context_class">thread</property>

    <!-- Disable the second-level cache -->
    <property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>

    <!-- Echo all executed SQL to stdout -->
    <property name="show_sql">true</property>

    <!-- Drop and re-create the database schema on startup -->
    <property name="hbm2ddl.auto">update</property>

  </session-factory>
</hibernate-configuration>


Note: The "hbm2ddl.auto" option turns on automatic generation of database schemas directly into the database.


The next subsections examine the configuration file more thoroughly.



The "hibernate.cfg.xml" Template


The session configuration file conforms to the syntax of an XML file, and also must conform to a document type definition (DTD). So we:
  • Declare it as XML ("<?xml ...")
  • Declare its doctype ("<!DOCTYPE ...")
  • Its root node ("<hibernate-configuration>")
  • And session-factory node

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
      "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
      "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">

<hibernate-configuration>
  <session-factory>

  </session-factory>
</hibernate-configuration>




Connection Settings


We add database connection settings:
  • We define the driver class - Java connects to a database through a driver class. We need to define the specific driver class that matches the database that we wish to connect. We want to connect to HSQLDB database, so we use the driver "org.hsqldb.jdbcDriver".
  • We define the connection URL ("connection.url"), the username ("connection.username") and the password ("connection.password")

    <!-- Database connection settings -->
    <property name="connection.driver_class">org.hsqldb.jdbcDriver</property>
    <property name="connection.url">jdbc:hsqldb:hsql://localhost</property>
    <property name="connection.username">sa</property>
    <property name="connection.password"></property>




Connection Pool


Using the connection settings define for our database we can now access it through Hibernate. Hibernate can manage several connections through a common design pattern of connection pool. Since our application is just for demo purposes, a single connection is enough, and we use the minimum connection pool size of one.


    <!-- JDBC connection pool (use the built-in) -->
    <property name="connection.pool_size">1</property>


Caution: The built-in Hibernate connection pool is in no way intended for production use. It lacks several features found on any decent connection pool.



SQL Dialect


Hibernate supports many relational databases, and it needs to generate SQL queries to persist its entities with the database. Although most relational databases support the standard ANSI SQL, each database has a slightly different SQL dialect. We need to define the SQL dialect that Hibernate will use to generate the SQL queries and persist its entities. We define here the HSQLDialect.


    <!-- SQL dialect -->
    <property name="dialect">org.hibernate.dialect.HSQLDialect</property>




Session Context


Hibernate is taking care for persisting its entities by using a Hibernate session. This session is active throughout a specific scope. We define the scope of the contextual session that Hibernate will use.


    <!-- Enable Hibernate's automatic session context management -->
    <property name="current_session_context_class">thread</property>



So how do we manage a contextual session? By using:

  • SessionFactory.getCurrentSession() method - Obtains the current Hibernate session
  • "org.hibernate.context.CurrentSessionContext" interface - This is the interface that is used to define a custom contract for the notion of a current session. You can use a predefined implementation of this interface, or you can implement it yourself and use a configuration parameter that points to your own implementor class.
  • Configuration parameter - "hibernate.current_session_context_class" - Defines the implementing class of a custom session context.


Out-of-the-box, Hibernate comes with three implementations of the "org.hibernate.context.CurrentSessionContext" interface:

  • org.hibernate.context.internal.JTASessionContext (aka "jta") - current sessions are tracked and scoped by a JTA transaction
  • org.hibernate.context.internal.ThreadLocalSessionContext (aka thread) - current sessions are tracked by thread of execution
  • org.hibernate.context.internal.ManagedSessionContext (aka managed) - current sessions are tracked by thread of execution. However, you are responsible to bind and unbind a Session instance with static methods on this class: it does not open, flush, or close a Session.

For the three out-of-the-box implementations, however, there are three corresponding short names: "jta", "thread", and "managed".



The Second Level Cache and Cache Policy


Hibernate Session can be configured to save its entities in a temporary cache of persistent data. All a cache implementation needs is to implement the "org.hibernate.cache.CacheProvider" interface.

You can define the caching strategy by:

  • org.hibernate.cache.CacheProvider - Specifying the name of a class that implements this interface
  • hibernate.cache.provider_class - Use this property to tell Hibernate which implementing class to use.

In our example application we do not use cache:


    <!-- Disable the second-level cache -->
    <property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>



There are several leading open-source cache implementations that support Hibernate. Several of them are bundled in the downloaded distribution of Hibernate.


Note: versions prior to 3.2 use EhCache as the default cache provider.


Some leading cache providers are:

  • EHCache
    • Provider class - "org.hibernate.cache.EhCacheProvider"
    • Type
      • memory
      • disk
      • transactional
      • clustered
    • Cluster Safe - yes
    • Query Cache Supported - yes
  • OSCache
    • Provider class - "org.hibernate.cache.OSCacheProvider"
    • Type
      • memory
      • disk
    • Cluster Safe - no
    • Query Cache Supported - yes




Log Configuration


In order to persist the entities Hibernate does many things for you behind the scenes. To understand more deeply how it works you can define the log level that Hibernate uses.


Hibernate uses the Apache Commons Logging, which is part of the Apache Commons project, and gives two choices of logging implementations:


You can control the log level with several configuration parameters:

  • On the "hibernate.cfg.xml" you can define the following properties:
    • show_sql - A boolean value <true | false> that instructs Hibernate to print the SQL queries that it runs and executes.
    • format_sql - A boolean value <true | false> that instructs Hibernate to format the SQL queries that it prints to the log
    • use_sql_comments - A boolean value <true | false> that instructs Hibernate to add comments on the SQL queries that it prints, that give hints of what it is actually trying to do.

  • Put a "log4j.properties" file in the Java classpath and add the following lines in it:
    • "log4j.logger.org.hibernate.SQL=debug" - This will do the same as the "show_sql" property on the "hibernate.cfg.xml"
    • "log4j.logger.org.hibernate.type=trace" - This will log the JDBC parameters that are passed to a query.


    Since most developers prefer Log4j Hibernate provides a sample Log4j configuration file. From the Hibernate distribution you can copy the "log4j.properties" file from the "etc/" directory to your "src" directory, next to "hibernate.cfg.xml".


    In our example application we define the log level of the executed queries:

        <!-- Echo all executed SQL to stdout -->
        <property name="show_sql">true</property>





    Automatic create of Database Schema



    To ease the development Hibernate gives you the option that the database schema will be dropped and recreated automatically according to the Hibernate Entity Mapping Associations. It will do that each time that you run you application.

    This is done by a helper property, "hbm2ddl.auto", as the example application shows:

        <!-- Drop and re-create the database schema on startup -->
        <property name="hbm2ddl.auto">update</property>





    Accessing the Session Factory


    Developers interact with Hibernate's session factory in order to manage persistent entities.

    We recommend accessing the session factory through a dedicated helper infrastructure class - Every application should supply an organized way or convention to manage its infrastructure operations. This is a best-practice and it also eases development. Since a Hibernate developer needs to interact with a Session Factory, we recommend to encapsulate it in a Session Factory Helper class.

    Later on we will go through the code of the Session Factory Helper class. Since we define in our session configuration file ("hibernate.cfg.xml") mappings to entities, we first need to define those entities.



    Session Factory Helper Class


    Hibernate is controlled and started by a "org.hibernate.SessionFactory" object. It is a thread-safe global object that is instantiated once. It is used to obtain "org.hibernate.Session" instances, that represents a single-threaded unit of work  (a single atomic piece of work to be performed).


    You (the Hibernate architect) need to store the "org.hibernate.SessionFactory" somewhere for easy access in application code. We use here a helper class for the SessionFactory:

    package org.hibernate.tutorial.util;

    import org.hibernate.SessionFactory;
    import org.hibernate.cfg.Configuration;

    public class HibernateUtil {
      private static final SessionFactory sessionFactory = buildSessionFactory();

      private static SessionFactory buildSessionFactory() {
        try {
          // Create the SessionFactory from hibernate.cfg.xml
          return new Configuration().configure().buildSessionFactory();
        }
        catch (Throwable ex) {
          // Make sure you log the exception, as it might be swallowed
          System.err.println("Initial SessionFactory creation failed." + ex);
          throw new ExceptionInInitializerError(ex);
        }
      }

      public static SessionFactory getSessionFactory() {
        return sessionFactory;
      }
    }

    We create a HibernateUtil helper class that takes care of startup and makes accessing the "org.hibernate.SessionFactory" more convenient. This class not only produces the global "org.hibernate.SessionFactory" reference in its static initializer; it also hides the fact that it uses a static Singleton.

    In an application server we can use instead "JNDI lookup" for convenience.

    If you give the "org.hibernate.SessionFactory" a name in your configuration, Hibernate will try to bind it to JNDI under that name after it has been built.

    Another, better option is to use a JMX deployment and let the JMX-capable container instantiate and bind a HibernateService to JNDI. Such advanced options are discussed later.




    Define the Event Entity


    Defining the Entity class


    Let's define now a concrete class for the Event entity:

    package org.hibernate.tutorial.domain;


    import java.util.Date;

    public class Event {
      private Long id;
      private String title;
      private Date date;

      public Event() {}

      public Long getId() {
        return id;
      }

      private void setId(Long id) {
        this.id = id;
      }

      public Date getDate() {
        return date;
      }

      public void setDate(Date date) {
        this.date = date;
      }

      public String getTitle() {
        return title;
      }

      public void setTitle(String title) {
        this.title = title;
      }



      private Set participants = new HashSet();

      public Set getParticipants() {
        return participants;
      }

      public void setParticipants(Set participants) {
        this.participants = participants;
      }  
    }

    As you can see this is just a simple JavaBean POJO class. It has the following properties:
    • id - The id property holds a unique identifier value for a particular event. We do not want to manually assign it a unique value, but prefer it to be generated automatically by the infrastructure. Hence it has a private setter method and a public getter method.
    • title.
    • date.
    All the properties in the Event class are bound to table columns on the db.



    Mapping the Event Entity


    We use here the mapping file "Event.hbm.xml", to map the Event entity to the database:

    <?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="org.hibernate.tutorial.domain">
      <class name="Event" table="EVENTS">
        <id name="id" column="EVENT_ID">
          <generator class="native"/>
        </id>
        <property name="date" type="timestamp" column="EVENT_DATE"/>
        <property name="title"/>

        <set name="participants" table="PERSON_EVENT" inverse="true">
          <key column="EVENT_ID"/>
          <many-to-many column="PERSON_ID" class="events.Person"/>
        </set>
      </class>
    </hibernate-mapping>


    The next subsections will go through the entity mapping file more thoroughly.




    The Mapping File Template


    Similar to the configuration of the Session Factory (see "Configuring the Session Factory"), the XML mapping file starts with an XML template:

    <?xml version="1.0"?>
    <!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">





    Define the package of the associated class


    The root element of the XML file declares the package of the associated class in an XML Entity Mapping file:

      <hibernate-mapping package="org.hibernate.tutorial.domain">
        [...]
      </hibernate-mapping>


    On this example we are going to associate a class from the package "org.hibernate.tutorial.domain".




    Associate an Entity name with a Database Table


    Each Hibernate entity is associated with a database table and is given a logical/symbolic name that the Hibernate Session is referencing for its persistency operations:

      <class name="Event" table="EVENTS">
      </class>


    We are associating here the "Event" class (from the package "org.hibernate.tutorial.domain") to an Entity identified with the name "Event".




    Mapping the Primary Key


    A Hibernate entity is mapped to specific data on a relational datastore. To map to specific data we need to define how an entity instance is mapped to a unique database surrogate primary key. In Hibernate you define:

    • A mapping between an Entity and a database surrogate - Every Hibernate entity must have a primary key bean property
    • The Hibernate's identifier generation strategy - When creating a new Hibernate entity, Hibernate needs to know how the primary key property is given a value.

        <id name="id" column="EVENT_ID">
          <generator class="native"/>
        </id>




    Note: "native" is no longer consider the best strategy in terms of portability. There are specifically 2 bundled enhanced generators:
    • org.hibernate.id.enhanced.SequenceStyleGenerator
    • org.hibernate.id.enhanced.TableGenerator




    Mapping Other Properties


    We need to tell Hibernate about the remaining properties of the entity class . By default, no properties are considered persistent:

        <property name="date" type="timestamp" column="EVENT_DATE"/>
        <property name="title"/>

    In the snippet above, Hibernate will search for the date and title properties, meaning it will search for getDate(), setDate(), getTitle() and setTitle() methods.

    The mapping of the "date" property includes two additional attributes:

    • "type" - Hibernate tries to determine the correct conversion from/to the entity property and the table column. In this case Hibernate cannot know what is the column datatype of the "date" property. It can either map an SQL "date", "timestamp" or "timedatatype. Thus we needs to define the "type" property.
    • "column" attribute - Hibernate by default uses the property name as the column name. The word "date" is reserved and cannot be mapped to a database column with a name "date", thus it needs to map it to a different column name. We use the "column" attribute to map the entity property "date" to the table column "EVENT_DATE".




    Binding the Mapping File


    We need to bind java instances to database schema. There are several ways to bind to the XML Mapping File (See "XML Entity Mappings"). We chose here to bind through explicit mapping:

        <mapping resource="org/hibernate/tutorial/domain/Event.hbm.xml"/>    



    We bind the xml mapping file "Event.hbm.xml" from the package "org.hibernate.tutorial.domain" to Hibernate Session Factory.




    The EventManager class


    To make it easy for a developer to manipulate Event entities, we will define a manager for Event entities:

    package org.hibernate.tutorial;


    import org.hibernate.Session;
    import java.util.*;
    import org.hibernate.tutorial.domain.Event;
    import org.hibernate.tutorial.util.HibernateUtil;

    public class EventManager {

      public static void main(String[] args) {
        EventManager mgr = new EventManager();
        if (args[0].equals("store")) {
          mgr.createAndStoreEvent("My Event", new Date());
        }
        else if (args[0].equals("list")) {
          List events = mgr.listEvents();
          for (int i = 0; i < events.size(); i++) {
            Event theEvent = (Event) events.get(i);
            System.out.println( "Event: " + theEvent.getTitle() + " Time: " + theEvent.getDate() );
          }
        }
        HibernateUtil.getSessionFactory().close();
      }

      private void createAndStoreEvent(String title, Date theDate) {
        Session session = HibernateUtil.getSessionFactory().getCurrentSession();
        session.beginTransaction();
        Event theEvent = new Event();
        theEvent.setTitle(title);
        theEvent.setDate(theDate);
        session.save(theEvent);
        session.getTransaction().commit();
      }

      private List listEvents() {
        Session session = HibernateUtil.getSessionFactory().getCurrentSession();
        session.beginTransaction();
        List result = session.createQuery("from Event").list();
        session.getTransaction().commit();
        return result;
      }

      private void addPersonToEvent(Long personId, Long eventId) {
        Session session = HibernateUtil.getSessionFactory().getCurrentSession(); 
        session.beginTransaction(); 
        Person aPerson = (Person) session.load(Person.class, personId); 
        Event anEvent = (Event) session.load(Event.class, eventId); 
        aPerson.getEvents().add(anEvent); 
        session.getTransaction().commit(); 
      }

    }


    The manager supports for now, creating new events ("createAndStoreEvent") and listing all events ("listEvents").

    We also create a startup point for our application - we added a "main()" method to the manager class. The main() method receives an argument of the requested operation (args[0]), and calls the method that corresponds to it.




    Storing objects


    In the "EventManager" class we define the "createAndStoreEvent()" method:

      private void createAndStoreEvent(String title, Date theDate) {
        Session session = HibernateUtil.getSessionFactory().getCurrentSession();
        session.beginTransaction();
        Event theEvent = new Event();
        theEvent.setTitle(title);
        theEvent.setDate(theDate);
        session.save(theEvent);
        session.getTransaction().commit();
      }

     It does the following:
    • Get a sessin for the current operation
        Session session = HibernateUtil.getSessionFactory().getCurrentSession();

    The getCurrentSession() method always returns the "current" unit of work, relative to the context that we configured in the hibernate.cfg.xml. We configured it to thread, and thus the context of a current unit of work is bound to the current Java thread that executes the application.

    org.hibernate.Session begins when the first call to getCurrentSession() is made for the current thread. It is then bound by Hibernate to the current thread. When the transaction ends, either through commit or rollback, Hibernate automatically unbinds the org.hibernate.Session from the thread and closes it for you. If you call getCurrentSession() again, you get a new org.hibernate.Session and can start a new unit of work. 

    Note: In order to demonstrate a simple example we use here an anti-pattern - transaction per operation. See Chapter 11, Transactions and Concurrency for more information about transaction handling and demarcation.

      • Begin a transaction for the current operation
        session.beginTransaction();

    In the above snippet we keep things simple and use a one-to-one granularity between a Hibernate org.hibernate.Session and a database transaction. To shield our code from the actual underlying transaction system we use the Hibernate org.hibernate.Transaction API.  In this particular case we are using JDBC-based transactional semantics, but it could also run with JTA.
      • Create a new Event object
        Event theEvent = new Event();
        theEvent.setTitle(title);
        theEvent.setDate(theDate);

      • Persist it on the session object, i.e. hand it over to Hibernate. At that point, Hibernate takes care of the SQL and executes an INSERT on the database.
        session.save(theEvent);


      • Commit the transaction
    session.getTransaction().commit();





    Loading objects


    To list stored events an option is added to the if statement of the main() method:

    else if (args[0].equals("list")) {
      List events = mgr.listEvents();
      for (int i = 0; i < events.size(); i++) {
        Event theEvent = (Event) events.get(i);
        System.out.println( "Event: " + theEvent.getTitle() + " Time: " + theEvent.getDate() );
      }
    }


    A new listEvents() method is also added:

      private List listEvents() {
        Session session = HibernateUtil.getSessionFactory().getCurrentSession();
        session.beginTransaction();
        List result = session.createQuery("from Event").list();
        session.getTransaction().commit();
        return result;
      }

    It does the following:

      • Like in the "createAndStoreEvent()" method, we get a sessin for the current operation
        Session session = HibernateUtil.getSessionFactory().getCurrentSession();


      • Like in the "createAndStoreEvent()" method, we begin a transaction for the current operation

        session.beginTransaction();


      • We load all existing Event objects from the database

        List result = session.createQuery("from Event").list();

    Here, we are using a Hibernate Query Language (HQL) query to load all existing Event objects from the database. Hibernate will generate the appropriate SQL, send it to the database and populate Event objects with the data. You can create more complex queries with HQL. See Chapter 14, HQL: The Hibernate Query Language for more information.

      • We commit the transaction:
                                session.getTransaction().commit();

                 return result;
        • And lastlly we return the resut:

      Mapping associations


      To create an association between entities we have to deal with the following attributs:
      1. Directionality - Unidirectional or Bidirectional
      2. Multiplicity
      3. Collection behavior.

      • Directionality - It is the direction of the association. It can be a Unidirectional association or Bidirectional association:
        • Unidirectional association - if we have two entities, A and B, and the association is defined only in one of them, then we have a Unidirectional association. If the association is defined only in entity A it means that you can use entity A to find the B entities that are associated with it, but you can not use entity B to find the A entities that are associated with it.
        • Bidirectional association - if we have two entities, A and B, and the association is defined in both of them, then we have a Bidirectional association. You can use entity A to find the B entities that are associated with it, and you can use entity B to find the A entities that are associated with it.

      • Multiplicity:
        • one-to-many
        • one-to-one
        • many-to-one
        • many-to-many

      • Collection behavior - Collection behavior means that if entity of type A defines an association to entity of type B, and entity of type A is associated with several elements of type B (xxx-to-many), then entity A must hold a collection of type B that it is associated with them. The association is mapped to one of the Java Collections Framework (JCF). Each implementation of the JCF implementations behaves differently. E.g. java.util.Set does not preserve the order of the elements but each element is unique, while java.util.List preserve the order of the elements but the elements are not unique.
      Let's add to the Event class an association. We will add people (the Person class) to the application and store a list of Event entities in which they participate.

      We will make an association with the following entity:

      package org.hibernate.tutorial.domain;


      public class Person {
        private Long id;
        private int age;
        private String firstname;
        private String lastname;

        public Person() {}

        private Set events = new HashSet();

        public Set getEvents() {
          return events;
        }

        public void setEvents(Set events) {
          this.events = events;
        }
        // Accessor methods for all properties, private setter for 'id'
      }


      And its mapping configuration - "Person.hbm.xml":

      <hibernate-mapping package="org.hibernate.tutorial.domain">
        <class name="Person" table="PERSON">
          <id name="id" column="PERSON_ID">
            <generator class="native"/>
          </id>


          <property name="age"/>
          <property name="firstname"/>
          <property name="lastname"/>
        </class>
      </hibernate-mapping>


      We also need to add its mappuing file to Hibernate's configuration:

      <mapping resource="events/Event.hbm.xml"/>
      <mapping resource="events/Person.hbm.xml"/>


      A Uni-Directional Set-based association


      • A unidirectional association is an association that exist from one entity to the other, but does not exist in the other direction.
      • A Set based association is an association that its Collection Behavior is based on the java.util.Set interface.

      First of all we need to know what are the assumptions on the association properties:
      • Multiplicity - A person can participate in an event and there are several participants in each event. This means that each Person can relate to zero or more Event entities, and each Event have several Person entities that participate in it - its multiplicity is <many-to-many>
      • Direction - We want to know in what events a person is participating in, but we do not need to know which of the persons participate in a certain event - a unidirectional association from person to events
      • Collection Behavior - The order of the events does not matter but each Event entity is unique - a collection behavior of Set-based association.

      Now lets see the code:

      • Add a collection of Event entities to the Person class:

      public class Person {
        private Set events = new HashSet();

        public Set getEvents() {
          return events;
        }

        public void setEvents(Set events) {
          this.events = events;
        }
      }


      By adding a collection of events to the Person class, you can easily navigate to the events for a particular person, without executing an explicit query - by calling Person.getEvents(). This method returns a multi-valued set of elements (a set of Event entities). Multi-valued associations are represented in Hibernate by one of the Java Collections Framework (JCF) contracts; here the collection behavior that the method returns matches a java.util.Set because the collection will not contain duplicate elements and the ordering is not relevant to our examples.
      • Map the added collection in "Person.hbm.xml":

      <class name="Person" table="PERSON">
        <id name="id" column="PERSON_ID">
          <generator class="native"/>
        </id>
        <property name="age"/>
        <property name="firstname"/>
        <property name="lastname"/>
        <set name="events" table="PERSON_EVENT">
          <key column="PERSON_ID"/>
          <many-to-many column="EVENT_ID" class="Event"/>
        </set>
      </class> 

        <set name="events" table="PERSON_EVENT">


      We use here a <many-to-many> association, or n:m association - An n:m association requires an association table. Each row in this table represents a link between a person and an event. The "table" attribute maps the association to the association table

      • We map the Person entitiy to the association table:
          <key column="PERSON_ID"/>


      Each primary key of the Person entity is mapped in the association table with the column "PERSON_ID".

      • We map the Event entity to the association table:
          <many-to-many column="EVENT_ID" class="Event"/>


      Each primary key of the Event entity is mapped in the association table with the column "EVENT_ID".


      The database schema for this mapping is therefore:

       _____________        __________________                      
      |             |      |                  |       _____________ 
      |   EVENTS    |      |   PERSON_EVENT   |      |             |
      |_____________|      |__________________|      |    PERSON   |
      |             |      |                  |      |_____________|
      | *EVENT_ID   | <--> |     *EVENT_ID    |      |             |
      |  EVENT_DATE |      |     *PERSON_ID   | <--> |  *PERSON_ID |
      |  TITLE      |      |__________________|      |   AGE       |
      |_____________|                                |   FIRSTNAME |
                                                     |   LASTNAME  |
                                                     |_____________|
                                                                    


      Adding Associated Data to an Entity


      Now we will bring some people and events together in a new method in EventManager:

        private void addPersonToEvent(Long personId, Long eventId) {
          Session session = HibernateUtil.getSessionFactory().getCurrentSession(); 
          session.beginTransaction(); 
          Person aPerson = (Person) session.load(Person.class, personId); 
          Event anEvent = (Event) session.load(Event.class, eventId); 
          aPerson.getEvents().add(anEvent); 
          session.getTransaction().commit(); 
        }

        • After loading a Person and an Event, we simply modify the collection using the normal collection methods.
        • We use here "automatic dirty checking" - There is no explicit call to update() or save()Hibernate automatically detects that the collection has been modified and needs to be updated. As long as your entities are in persistent state, that is, bound to a particular Hibernate org.hibernate.Session, Hibernate monitors any changes and executes SQL in a write-behind fashion.
        • Flushing - The process of synchronizing the memory state with the database, usually only at the end of a unit of work, is called flushing. In our code, the unit of work ends with a commit, or rollback, of the database transaction.


      • We load the correct Person entity:

          Person aPerson = (Person) session.load(Person.class, personId); 


      • We load the correct Event entity:
          Event anEvent = (Event) session.load(Event.class, eventId); 


      • We add the associated Event entity to the Person entity:
          aPerson.getEvents().add(anEvent); 


      • We commit the transaction
          session.getTransaction().commit(); 



      Bi-Directional Set-based Association


      Lets make the uni-directional association from the previous section, between Person entity and Event entity, to work from both sides so that it will be a bi-directional association. The database schema does not change, so you will still have many-to-many multiplicity.
      • First, add a collection of participants to the Event class:

        private Set participants = new HashSet();

        public Set getParticipants() {
          return participants;
        }

        public void setParticipants(Set participants) {
          this.participants = participants;
        }  

      • Now map this side of the association in "Event.hbm.xml":

      <set name="participants" table="PERSON_EVENT" inverse="true">
        <key column="EVENT_ID"/>
        <many-to-many column="PERSON_ID" class="events.Person"/>
      </set>

      • "key" element - maps to the key in the association table
      • "many-to-many" element - maps "n:m" association between "EVENT_ID" and "PERSON_ID" columns
      • "inverse="true"" - The most important addition in here, which is an attribute on the "set" element of the Event's collection mapping. What this means is that Hibernate should take the other side, the Person class, when it needs to find out information about the link between the two. In other words, you use "inverse=”true”" on the relationship owner. All bi-directional associations need one side as inverse. In a "one-to-many" association it has to be the many-side, and in "many-to-many" association you can select either side.
      • Add proxy methods to add and remove events to a Person:

      protected Set getEvents() {
        return events;
      }

      protected void setEvents(Set events) {
        this.events = events;
      }

      public void addToEvent(Event event) {
        this.getEvents().add(event);
        event.getParticipants().add(this);
      }

      public void removeFromEvent(Event event) {
        this.getEvents().remove(event);
        event.getParticipants().remove(this);
      }


      As mentioned above, the association between an Event entity and a Person entity is bi-directional, which means that both of them have Set collections of the associated entities. We have to keep the associated entities in correlation with one another so that the association will not get broken.

      To do so we shield the "events" property and set the scope of its get/set methods to protected, while we add proxy methods to add/remove an event for a person. These methods take care of keeping the association complete by adding/removing to both of the entities.




      Inheritance strategy (v4.2)

      Several strategies are possible to persist a class hierarchy:

      • Single table per class hierarchy strategy - A single table hosts all the instances of a class hierarchy
      • Joined subclass strategy - One table per class and subclass is present and each table persist the properties specific to a given subclass. The state of the entity is then stored in its corresponding class table and all its superclasses
      • Table per class strategy - One table per concrete class and subclass is present and each table persist the properties of the class and its superclasses. The state of the entity is then stored entirely in the dedicated table for its class.



      Single table per class hierarchy strategy


      With this approach the properties of all the subclasses in a given mapped class hierarchy are stored in a single table.

      Each subclass declares its own persistent properties and subclasses. Version and id properties are assumed to be inherited from the root class. Each subclass in a hierarchy must define a unique discriminator value. If this is not specified, the fully qualified Java class name is used.

      @Entity
      @Inheritance(strategy=InheritanceType.SINGLE_TABLE)
      @DiscriminatorColumn(
          name="planetype",
          discriminatorType=DiscriminatorType.STRING
      )
      @DiscriminatorValue("Plane")
      public class Plane { ... }

      @Entity
      @DiscriminatorValue("A320")
      public class A320 extends Plane { ... }          


      In hbm.xml, for the table-per-class-hierarchy mapping strategy, the <subclass> declaration is used. For example:

      <subclass
              name="ClassName"                                   (1)
              discriminator-value="discriminator_value"          (2)
              proxy="ProxyInterface"                             (3)
              lazy="true|false"                                  (4)
              dynamic-update="true|false"
              dynamic-insert="true|false"
              entity-name="EntityName"
              node="element-name"
              extends="SuperclassName">

              <property .... />
              .....
      </subclass>


      1. name - the fully qualified class name of the subclass.
      2. discriminator-value (optional - defaults to the class name) - a value that distinguishes individual subclasses.
      3. proxy (optional) - specifies a class or interface used for lazy initializing proxies.
      4. lazy (optional - defaults to true) - setting lazy="false" disables the use of lazy fetching.




      Discriminator


      Discriminators are required for polymorphic persistence using the table-per-class-hierarchy mapping strategy. It declares a discriminator column of the table. The discriminator column contains marker values that tell the persistence layer what subclass to instantiate for a particular row. Hibernate Core supports the follwoing restricted set of types as discriminator column: string, character, integer, byte,short, boolean, yes_no, true_false.

      Use the @DiscriminatorColumn to define the discriminator column as well as the discriminator type.

      Note: The enum DiscriminatorType used in javax.persitence.DiscriminatorColumnonly contains the values STRING, CHAR and INTEGER which means that not all Hibernate supported types are available via the @DiscriminatorColumn annotation.

      You can also use @DiscriminatorFormula to express in SQL a virtual discriminator column. This is particularly useful when the discriminator value can be extracted from one or more columns of the table. Both @DiscriminatorColumn and @DiscriminatorFormula are to be set on the root entity (once per persisted hierarchy).

      @org.hibernate.annotations.DiscriminatorOptions allows to optionally specify Hibernate specific discriminator options which are not standardized in JPA. The available options are force and insert:
      • The force attribute is useful if the table contains rows with "extra" discriminator values that are not mapped to a persistent class. This could for example occur when working with a legacy database. If force is set to true Hibernate will specify the allowed discriminator values in the SELECT query, even when retrieving all instances of the root class.
      • The second option - insert - tells Hibernate whether or not to include the discriminator column in SQL INSERTs. Usually the column should be part of the INSERT statement, but if your discriminator column is also part of a mapped composite identifier you have to set this option to false.

      Tip: There is also a @org.hibernate.annotations.ForceDiscriminator annotation which is deprecated since version 3.6. Use @DiscriminatorOptions instead.

      Finally, use @DiscriminatorValue on each class of the hierarchy to specify the value stored in the discriminator column for a given entity. If you do not set @DiscriminatorValue on a class, the fully qualified class name is used.

      @Entity
      @Inheritance(strategy=InheritanceType.SINGLE_TABLE)
      @DiscriminatorColumn(
          name="planetype",
          discriminatorType=DiscriminatorType.STRING
      )
      @DiscriminatorValue("Plane")
      public class Plane { ... }

      @Entity
      @DiscriminatorValue("A320")
      public class A320 extends Plane { ... }          
      In hbm.xml, the <discriminator> element is used to define the discriminator column or formula:
      <discriminator
              column="discriminator_column"                      (1)
              type="discriminator_type"                          (2)
              force="true|false"                                 (3)
              insert="true|false"                                (4)
              formula="arbitrary sql expression"                 (5)
      />


      1. column (optional - defaults to class): the name of the discriminator column.
      2. type (optional - defaults to string): a name that indicates the Hibernate type
      3. force (optional - defaults to false): "forces" Hibernate to specify the allowed discriminator values, even when retrieving all instances of the root class.
      4. insert (optional - defaults to true): set this to false if your discriminator column is also part of a mapped composite identifier. It tells Hibernate not to include the column in SQL INSERTs.
      5. formula (optional): an arbitrary SQL expression that is executed when a type has to be evaluated. It allows content-based discrimination.

      Actual values of the discriminator column are specified by the discriminator-value attribute of the<class> and <subclass> elements.

      The formula attribute allows you to declare an arbitrary SQL expression that will be used to evaluate the type of a row. For example:

      <discriminator
          formula="case when CLASS_TYPE in ('a', 'b', 'c') then 0 else 1 end"
          type="integer"/>





      Joined subclass strategy

      Each subclass can also be mapped to its own table. This is called the table-per-subclass mapping strategy. An inherited state is retrieved by joining with the table of the superclass. A discriminator column is not required for this mapping strategy. Each subclass must, however, declare a table column holding the object identifier. The primary key of this table is also a foreign key to the superclass table and described by the @PrimaryKeyJoinColumns or the <key> element.

      @Entity @Table(name="CATS")
      @Inheritance(strategy=InheritanceType.JOINED)
      public class Cat implements Serializable { 
          @Id @GeneratedValue(generator="cat-uuid") 
          @GenericGenerator(name="cat-uuid", strategy="uuid")
          String getId() { return id; }

          ...
      }

      @Entity @Table(name="DOMESTIC_CATS")
      @PrimaryKeyJoinColumn(name="CAT")
      public class DomesticCat extends Cat { 
          public String getName() { return name; }
      }            


      Note:
      The table name still defaults to the non qualified class name. Also if@PrimaryKeyJoinColumn is not set, the primary key / foreign key columns are assumed to have the same names as the primary key columns of the primary table of the superclass.

      In hbm.xml, use the <joined-subclass> element. For example:

      <joined-subclass
              name="ClassName"                                   (1)
              table="tablename"                                  (2)
              proxy="ProxyInterface"                             (3)
              lazy="true|false"                                  (4)
              dynamic-update="true|false"
              dynamic-insert="true|false"
              schema="schema"
              catalog="catalog"
              extends="SuperclassName"
              persister="ClassName"
              subselect="SQL expression"
              entity-name="EntityName"
              node="element-name">

              <key .... >

              <property .... />
              .....
      </joined-subclass>


      1. name: the fully qualified class name of the subclass.
      2. table: the name of the subclass table.
      3. proxy (optional): specifies a class or interface to use for lazy initializing proxies.
      4. lazy (optional, defaults to true): setting lazy="false" disables the use of lazy fetching.

      Use the <key> element to declare the primary key / foreign key column. The mapping at the start of the chapter would then be re-written as:

      <?xml version="1.0"?>
      <!DOCTYPE hibernate-mapping PUBLIC
              "-//Hibernate/Hibernate Mapping DTD//EN"
              "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">

      <hibernate-mapping package="eg">

              <class name="Cat" table="CATS">
                      <id name="id" column="uid" type="long">
                              <generator class="hilo"/>
                      </id>
                      <property name="birthdate" type="date"/>
                      <property name="color" not-null="true"/>
                      <property name="sex" not-null="true"/>
                      <property name="weight"/>
                      <many-to-one name="mate"/>
                      <set name="kittens">
                              <key column="MOTHER"/>
                              <one-to-many class="Cat"/>
                      </set>
                      <joined-subclass name="DomesticCat" table="DOMESTIC_CATS">
                          <key column="CAT"/>
                          <property name="name" type="string"/>
                      </joined-subclass>
              </class>

              <class name="eg.Dog">
                      <!-- mapping for Dog could go here -->
              </class>

      </hibernate-mapping>





      Attached and Detached Entity


      You can load Person and Event in different units of work. Or you can modify an object outside of a org.hibernate.Session when it is not in persistent state. If it was persistent before, this state is called detached. You can even modify a collection when it is detached:

      private void addPersonToEvent(Long personId, Long eventId) {
        Session session = HibernateUtil.getSessionFactory().getCurrentSession();
        session.beginTransaction();

        Person aPerson =
          (Person) session.createQuery("select p from Person p left join fetch p.events where p.id = :pid")
            .setParameter("pid", personId)
            .uniqueResult();
        // Eager fetch the collection so we can use it detached
        Event anEvent = (Event) session.load(Event.class, eventId); 
        session.getTransaction().commit();
        // End of first unit of work

        aPerson.getEvents().add(anEvent);
        // aPerson (and its collection) is detached // Begin second unit of work
        Session session2 = HibernateUtil.getSessionFactory().getCurrentSession();
        session2.beginTransaction();
        session2.update(aPerson); // Reattachment of aPerson
        session2.getTransaction().commit();
      }



      The call to update() makes a detached object persistent again by binding it to a new unit of work, so any modifications you made to it while detached can be saved to the database. This includes any modifications (additions/deletions) you made to a collection of that entity object.

      Primary-Key / Unique-Identifier Generation Strategy

      All persistent entity classes need to hold a unique identifier value. This identifier is designated a generation strategy, either a default one, or specific one defined by the Hibernate architect. There mainly two types of generation strategy:
      • Without generation strategy (Default) - The id is assigned manually by the programmer
      • With generation strategy - The id is created automatically by the Hibernate infrastructure.
      Hibernate supports several generation strategies. It supports database generated, globally unique, as well as application assigned, identifiers. Identifier value generation is also one of Hibernate's many extension points and you can plugin in your own strategy.

      The idea behind these generators is to port the actual semantics of the identifer value generation to the different databases. For example, the org.hibernate.id.enhanced.SequenceStyleGenerator mimics the behavior of a sequence on databases which do not support sequences by using a table.

      Hibernate Visible Scopes

      Hibernate can access public, private, and protected accessor methods fields directly.

      Hibernate Constructors

      Each entity requires a no-argument constructor, with a visibility of package or public.

      Hibernate Document-Type Definition (DTD)

      Hibernate DTD file is included in hibernate-core.jar (and also in hibernate3.jar, if using the distribution bundle).

      Hibernate Mapping Types

      The types declared and used in the mapping files (the "type" property) are not Java data types or SQL database types. These types are  Hibernate mapping types. Hibernate will try to determine the correct conversion and mapping type itself if the type attribute is not present in the mapping. In some cases this automatic detection using Reflection on the Java class might not have the default you expect or need. For example, in the case of a "date" property, Hibernate cannot know if the property, which is of java.util.Date, should map to a SQL date, timestamp, or time column.

      Relationship Owner


      When using Hibernate you here a lot the term "Relationship Owner". The Relationship Owner is the entity that holds the association. For example, if the association between Students and Course_of_study is maintained in the Students entity/table, by a foreign key of "Course_of_study_id", so the Relationship Owner is the Students entity.





























          <mapping resource="org/hibernate/tutorial/domain/Person.hbm.xml"/>




      5.2.2   Mapping the Person Entity


      Here is the Person Entity mapping file. The file structure is very similar to the Event mapping file, and you can use it to get a reminder of the file syntax (see "Mapping the Event Entity"). 

      <hibernate-mapping package="org.hibernate.tutorial.domain">
        <class name="Person" table="PERSON">
          <id name="id" column="PERSON_ID">
            <generator class="native"/>
          </id>


          <property name="age"/>
          <property name="firstname"/>
          <property name="lastname"/>
        </class>
      </hibernate-mapping>


      XML Entity Mappings




      Hibernate supports entity mapping of java instances to database schema using XML mappings. It is also called "hbm.xmlmappings, because by convention each mapped entity has its own XML mapping file, and the entity mapping file is called after the class that it maps in the following format: "<mapped-class-lower-case-name>.hbm.xml".



      =========================================================
      Consider the following example: A user can select a preferred language. Each language code has a description attached to it. When the user changes his preferred language the description of each language also changes according to the new preferred language that was chosen.

      The Need


      We needed to have some kind of map of different descriptions for our language (i.e. we need to describe each language in different local languages). Revising our Java code, we get something like this:

      private Map<String, String> getMap() {
        return this.map;
      }

      private void setMap(Map<String, String> map) {
        this.map = map;
      }

      public String getDefaultDescription() {
        return getMap().get(Locale.ENGLISH.toString());
      }

      public String getDescription(String language) {
        String description = getMap().get(language);
        if (StringUtils.isBlank(description)) {
          Locale locale = new Locale(language);
          description = getMap().get(locale.getLanguage());
        }
        return StringUtils.isBlank(description) ?
               getDefaultDescription() :
               description;
      }

      Now the trick: how to annotate this?

      The Schema

      It was easy to imagine what the final tables should look like:



      What wasn’t as simple was imagining the set of annotations to accomplish this.

      The CollectionOfElements Pattern (Deprecated)

      We weren’t interested in having another class to hold the language descriptions. We wanted simple String elements in our Map. That led us to the “CollectionOfElements” pattern in Hibernate.

      Define the Pattern

      We tried this:

      @CollectionOfElements
      private Map<String, String> getMap() {
        return this.map;
      private void setMap(Map<String, String> map) { 
        this.map = map; 
      }


      But there were two key things to do here:
      • Assign a table name of our choosing; and
      • Assign column names that we favoured.

      Define the Mapped Table


      First, we added a JoinTable annotation to change the name that Hibernate wanted to generate:

      @CollectionOfElements
      @JoinTable(name="language_description")
      private Map<String, String> getMap() {
        return this.map;
      }

      Define the Columns

      Next, we needed to deal with each of the three columns. Each column plays a very different role in the final result, and the name for each column was configured very differently.

      Define the Primary Key

      First, the key to the parent (LANGUAGE_DESC) table was set in the JoinColumn annotation (but the annotation was put in a funny spot):

      @CollectionOfElements
      @JoinTable(name="language_description", 
                 joinColumns = @JoinColumn(name="language_code")) 
      private Map<String, String> getMap() {
        return this.map;
      }

      Define the Key of the Java Collection

      Next, we wanted define the column that acts as the key to the map. We can use the MapKey annotation for that. Careful, however, because there are two different implementations of this annotation. We used the Hibernate implementation:
      @CollectionOfElements
      @JoinTable(name="language_description", 
                 joinColumns = @JoinColumn(name="language_code")) @MapKey(columns={@Column(name="for_language",length=5)}) 
      private Map<String, String> getMap() {
        return this.map;
      }


      Notice that we also set the length of this field, since we know that it’ll never be more than 5 characters.

      Define the Value of the Java Collection

      Finally, we want to define the name of the String that’s kept as the value of the map:
      @CollectionOfElements
      @JoinTable(name="language_description", 
                 joinColumns = @JoinColumn(name="language_code"))
      @MapKey(columns={@Column(name="for_language",length=5)}) @Column(name="description") 
      private Map<String, String> getMap() {
        return this.map;
      }


      After we added these annotations, we ended up with the table structure that we were looking for.