Tuesday, October 18, 2011

JPA Examples

In our sample application, the following packages contain the examples on the topics as the package names suggest. We have reused the annotated ORM classes from the respective packages that start with "annotation".



Execute the classes in the packages that start with "jpa" one by one and verify the results in the eclipse console and as well as in the HSQL DB manager as explained in the previous examples.

JPA + Hibernate with Spring

Spring provides support for JPA in two flavors. We can either use JpaTemplate or JpaDaoSupport. Let us look into both of them one by one.

Let us go to the package jpa.com.demo.JPAwithSpring and look into the files over there:

SpringForJPA.xml:

There are two types of entity managers. They are Application managed entity managers and Container managed entity managers. Each of these entity managers are obtained from their own entity manager factories. (i.e)
createEntityManagerFactory() of PersistenceProvider produces application managed entity manager.

createContainerEntityManagerFactory() of PersistenceProvider produces container managed entity manager.

Hence spring support both versions of the entity managers. In our example we used the container managed entity manager.

<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter">

<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="true" />
<property name="generateDdl" value="false" />

<property name="database" value="HSQL" />

<property name="databasePlatform" value="org.hibernate.dialect.HSQLDialect" />
</bean>
</property>
<property name="persistenceUnitName" value="jpaDemo" />
</bean>

* The entityManagerFactory represents an instance of LocalContainerEntityManagerFactoryBean * The attribute jpaVendorAdapter specifies the underlying ORM engine, here it is Hibernate.
* persistenceUnitName specifies the name of the persistence unit name in the persistence.xml

JpaTemplate:

<bean id="jpaTemplate" class="org.springframework.orm.jpa.JpaTemplate">
<property name="entityManagerFactory" ref="entityManagerFactory" /> </bean>

* In the above xml configuration, the entityManagerFactory is wired into the JpaTemplate class which will produce entity managers.


<bean id="bookTemplateDao" class="jpa.com.demo.JPAwithSpring.BookJpaTemplateDaoImpl">
<property name="jpaTempate" ref="jpaTemplate" />
</bean>

* when the instance of the class BookJpaTemplateDaoImpl which has a reference to JpaTemplate is created from Spring, it is injected with an object of JpaTemplate as given above.

* The jpaTemplate then provides the methods like persist(), find() and getEntityManagerFactory() to deal with underlying database through the ORM engine. Look at the class BookJpaTemplateDaoImpl.java for more details.

Execute the class JpaTemplateExecutor.java from the package jpa.com.demo.JPAwithSpring and verify the results in the eclipse console as well as in the HSQL DB manager as follows.


JpaDaoSupport:

Instead of having a reference variable of type JpaTemplate, we can directly extend a class named JpaDaoSupport and directly use the method getJapTemplate() which will give the same methods that we have used from jpaTemplate.

<bean id="bookDaoSupportDao" class="jpa.com.demo.JPAwithSpring.BookJpaDaoSupportDaoImpl">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>

* When the instance of a class BookJpaDaoSupportDaoImpl which extends the JpaDaoSupport is created from Spring, it is injected with an object of LocalContainerEntityManagerFactoryBean in the entityManagerFactory property as given above. For more details look at the class BookJpaDaoSupportDaoImpl.java.

Let us now execute the class JpaDaoSupportDaoExecutor.java and verify the results as explained above.



JPA Hello World Program

JPA is a set of specifications with respect to persistence given as part of EJB 3.0. It defines a set of interfaces which are available in the package javax.persistence. Vendors like Hibernate provides meaning implementation for the interfaces and specifications defined in JPA. JDK 5.0 or above is required to support JPA as it uses annotations which are defined starting from JDK 5.0. Here, we will see the examples of JPA with hibernate implementation. At the time of writing this blog, in order to support hiberntate implementation the following jars are required in the class path.


JPA in detail:

JPA requires a folder named META-INF in the class path and this folder is required to contain a xml file named persistence.xml. This xml file will have the JPA configuration details. JPAs specification concentrates on specifying persistence of classes using Java5 annotations, but you can also specify the persistence using metadata. You can define the MetaData in files of any name but the default is "orm.xml", stored under /META-INF MetaData mapping files for JPA have to match the format defined by the XSD for that file.

Primary programming interfaces in Java Persistence:

javax.persistence.Persistence— A startup class that provides a static method for the creation of an EntityManagerFactory.
■ javax.persistence.EntityManagerFactory—
The equivalent to a Hibernate SessionFactory. This runtime object represents a particular persistence unit. It’s thread-safe, is usually handled as a singleton, and provides methods for the creation of EntityManager instances.
■ javax.persistence.EntityManager—
The equivalent to a Hibernate Session.This single-threaded, nonshared object represents a particular unit of work for data access. It provides methods to manage the lifecycle of entity instances and to create Query instances.
■ javax.persistence.Query—
This is the equivalent to a Hibernate Query. An object is a particular JPA query language or native SQL query representation, and it allows safe binding of parameters and provides various methods for the execution of the query.
■ javax.persistence.EntityTransaction—
This is the equivalent to a Hibernate Transaction, used in Java SE environments for the demarcation of RESOURCE_LOCAL transactions. In Java EE, you rely on the standardized javax.transaction.UserTransaction interface of JTA for programmatic transaction demarcation.

The persistence.xml:

Following is the persistence.xml we have used in our example. It is required to be placed inside the folder META-INF.


<persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
version="1.0">

<persistence-unit name="jpaDemo">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<properties>
<property name="hibernate.archive.autodetection" value="class" />
<property name="hibernate.show_sql" value="true" />
<property name="hibernate.format_sql" value="true" />
<property name="hibernate.connection.driver_class" value="org.hsqldb.jdbcDriver" />
<property name="hibernate.connection.url" value="jdbc:hsqldb:hsql://localhost" />
<property name="hibernate.connection.username" value="sa" />
<property name="hibernate.connection.password" value="" />
<property name="hibernate.c3p0.min_size" value="5" />
<property name="hibernate.c3p0.max_size" value="20" />
<property name="hibernate.c3p0.timeout" value="300" />
<property name="hibernate.c3p0.max_statements" value="50" />

<property name="hibernate.c3p0.idle_test_period" value="3000" />
<property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect" />
<property name="hibernate.hbm2ddl.auto" value="create" />
</properties>
</persistence-unit>
</persistence>

* The EntityManagerFactory represents a particular logical data-source configuration in JPA. The configuration of an EMF, together with a set of mapping metadata is called a persistence unit. Every persistent unit needs a name and in our example we named the persistent unit as "jpaDemo".

* The <provider> tag specifies that the underlying ORM engine is Hibernate.

* The rest of the configurations are the hibernate configuration details which will normally be in the hibernate.cfg.xml.

Hello World Example:

Let us go to the package jpa.com.demo.HelloWorld and execute the class HelloWorldExecutor.java

EntityManagerFactory emf = Persistence.createEntityManagerFactory("jpaDemo");

EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();

Hello hello = new Hello();
hello.setName("Johnson");
hello.setMessage("Welcome");
em.persist(hello);
tx.commit();
em.close();

emf.close();

* When the program is executed, the Persistence.createEntityManagerFactory tries to find the persistent unit named "jpdDemo". It searches the classpath for all META-INF/persistence.xml files and then configures the EMF if a match is found.
* The persistence provider tries to find all annotated classess and all Hibernate XML mapping files in the build output directory. Hence automatic detection of annotated classes and xml mapping files is done in JPA.
* Here we reuse the annotated class Hello.java from the package annotation.com.demo.helloworld

Once the
HelloWorldExecutor.java is executed, verify the results in the eclipse console and as well as in the HSQL DB manager as follows.






Hibernate Criteria Query examples

Hibernate supports a feature that helps us to build queries dynamically. The org.hibernate.Criteria is the interface used for this purpose. Criteria is useful when we are supposed to apply a multiple complicated search criteria on the queries.

For a Criteria query, a Criterion Object should be constructed (i.e) a call to createCriteria() passing the class of the objects we want the query to return.

Let us go the package com.demo.CriteriaExamples and execute the class CriteriaExampleExecutor.java

Criteria Example:
Following is an example that will all the instances of the class Employee.

Criteria criteria = session.createCriteria(Employee.class);
List critList = criteria.list();
for(Object objList: critList)
System.out.println("Employee Name is "+ ((Employee)objList).getEmpName());

Limiting the number of rows returned:
This is particularly useful in pagination.

Criteria criteria = session.createCriteria(Employee.class).setMaxResults(2);
critList = criteria.list();
System.out.println("Number of rows returned "+ critList.size());
for(Object objList: critList)
System.out.println("Employee Name is "+ ((Employee)objList).getEmpName());



Narrowing the result set:

Restrictions class provides factory methods for built-in Criterion types. In our example we have used some of the factory methods like Restrictions.like(), Restrictions.between(), Restrictions.isNotNull().

Criteria criteria = session.createCriteria(Employee.class).add(Restrictions.like("empName", "Ana%"));
critList = criteria.list();
for(Object objList: critList)
System.out.println("Employee Name is "+ ((Employee)objList).getEmpName());


Ordering the Result Set:

The class Order provides the factoy methods asc() and desc() to order objects based on any particular property.


Criteria criteria = session.createCriteria(Employee.class).addOrder(Order.asc("empName"))
.addOrder(Order.desc("salary"));
critList = criteria.list();
for(Object objList: critList)
System.out.println("Employee Name is "+ ((Employee)objList).getEmpName() + " Employee Salary is " + ((Employee)objList).getSalary());



Logical and Comparison Operators available in Restrictions Class:

All regular SQL comparison operators are available in the Restrictions class. The methods Restrictions.or() and Restrictions.and() will serve the Logical operators.

Criteria criteria = session.createCriteria(Employee.class).add(Restrictions.or(
Restrictions.gt("salary", new Integer(23000)), Restrictions.ge("age", new Integer(30))));
critList = criteria.list();
for(Object objList: critList)
System.out.println("Employee Name salary is more than 23000 or whose age is greater than or equal to 30 is "+ ((Employee)objList).getEmpName());


Aggregate Functions():

Projections class serves the factory methods which can be used as the aggregate functions as follows.

critList = session.createCriteria(Employee.class).setProjection(Projections.max("salary")).list();
System.out.println("Maximum salary is "+ critList.get(0));
critList = session.createCriteria(Employee.class).setProjection(Projections.min("salary")).list();
System.out.println("Minimum salary is "+ critList.get(0));
critList = session.createCriteria(Employee.class).setProjection(Projections.rowCount()).list();
System.out.println("Total employees "+ critList.get(0));
critList = session.createCriteria(Employee.class).setProjection(Projections.avg("age")).list();
System.out.println("Average employee age "+ critList.get(0));
critList = session.createCriteria(Employee.class).setProjection(Projections.sum("salary")).list();
System.out.println("Sum of all the salaries "+ critList.get(0));



Also, Projections class will help us to select exactly the objects or the properties of objects we need in the query result as follows.

session.createCriteria(Employee.class).setProjection(Projections.projectionList().add(Projections.id())
.add(Projections.property("empName"))
.add(Projections.property("age"))
);

Hibernate HQL examples

The Hibernate Query Language (HQL) is similar to SQL. When compared to SQL, HQL is completely Object Oriented and hence it uses class names in the place of table names and property names in the place of column names. HQL understands inheritance, polymorphism and association. HQL is not case sensitive.

Let us go the package com.demo.HQLexamples and look into HQLexampleExecutor.java

HQL From Clause:

List studentList = session.createQuery(" from Student ").list();

for(Object stud : studentList){
System.out.println("Student Name is "+ ((Student)stud).getStudentName());
Set courses = ((Student)stud).getCourses();
System.out.println("Courses to which this student is associated");
for(Object course: courses)
System.out.println(((Course)course).getCourseName());
}



* The session.createQuery creates an instance of type org.hibernate.Query and the list() method of Query interface is actually the place where the execution of query starts.
* The from clause returns all the instances of a class.
* Objects can be retrieved by iterating the list.

HQL Joins:

Hibernate supports inner join, left outer join, right outer join, full join. In the following example, the query returns an array of objects ( the parent and its associated objects). Pay attention while iterating the list as follows.

List joinList = session.createQuery("from Student as s inner join s.courses").list();
Iterator ite = joinList.iterator();
while(ite.hasNext()){
Object [] objects = (Object []) ite.next();
Student student = (Student)objects[0];
Course course = (Course)objects[1];
System.out.println("Student Name " + student.getStudentName());
System.out.println("Course Name "+ course.getCourseName());
}


HQL Select Clause:

The select clause actually decides which objects and properties to return in the query result set. In the following example it returns only the Student objects and not the Course objects even though they are associated with the Student objects.

List selectList = session.createQuery("select distinct s from Student as s inner join s.courses").list(); //now only Student object is returned and not the Course object
for(Object sl : selectList)
System.out.println("Student Name "+ ((Student)sl).getStudentName());


HQL Aggregate functions:

In HQL, the aggregate functions like sum(), max(), min(), count() can be applied the properties and the results can be returned in the queries.

List aggreList = session.createQuery("select count(distinct s.studentName) from Student as s inner join s.courses").list();
System.out.println("Total Number of Students "+ aggreList.toString());

HQL Where Clause:

The where clause is used to filter the list of objects returned. Have a look at the syntax for the place holder in the where clause (:sname).

List whereList = session.createQuery("select distinct s from Student as s inner join s.courses where s.studentName= :sname").setParameter("sname","Prathap Kumar").list();//The where clause allows you to refine the list of instances returned.
for(Object wl: whereList)
System.out.println("Student Id is "+ ((Student)wl).getId());


HQL Order by Clause:

The objects returned in the query can be ordered on any property or component.

List orderList = session.createQuery("select s from Student s order by s.studentName asc").list();
for(Object ol : orderList)
System.out.println("Student name in ascending order "+ ((Student)ol).getStudentName());


HQL Group By Clause:

The aggregate values returned from a query can be grouped on any property or component.

List groupList = session.createQuery("select c.courseName, count(distinct c.courseName) from Student as s, Course c inner join s.courses group by c.courseName").list(); //A query that returns aggregate values can be grouped by any property of a returned class or components
ite = groupList.iterator();
while(ite.hasNext()){
Object [] objects = (Object []) ite.next();
System.out.println("Course Name is "+ objects[0]);
System.out.println("Count representation of the above course "+ objects[1]);
}

HQL Subqueries:

Hibernate supports subqueries within queries for the databases that allows subselects.
A subquery must be surrounded by parentheses.

List subList = session.createQuery("select s from Student s where s.studentName not in (select distinct s from Student as s inner join s.courses where s.studentName= 'Sekar')").list();
System.out.println("List size "+ subList.size());
for(Object sl: subList)
System.out.println("Student Name from the sub query is "+ ((Student)sl).getStudentName());


Native SQL Queries:

Hibernate also supports native SQL queries. We can directly use the native SQL queries in the place of HQL queries with one minor change. The method session.
createSQLQuery() should be used instead of session.createQuery() as follows.

List nativeSqlList = session.createSQLQuery("select * from STUDENTS").list(); // STEDENTS refer the actual table name
ite = nativeSqlList.iterator();
while(ite.hasNext()){
Object [] objects = (Object []) ite.next();
System.out.println("Student Id "+ objects[0]);
System.out.println("Student name "+ objects[1]);
}

The result set of a native SQL query can be converted into entity or object of a specific class by invoking a method addEntity() as follows.

List nativeRsHandlinglList = session.createSQLQuery("select * from COURSES").addEntity(Course.class).list(); // COURSES refer the actual table name
for(Object nativeList : nativeRsHandlinglList)
System.out.println("Course name is "+ ((Course)nativeList).getCourseName());

Named HQL:

The HQL queries can be named and embedded into the hibernate mapping file and can be retrieved using their respective names. The scope of the names of the HQL queries are globally visible.

Have a look at the namedQueries.hbm.xml file in the package com.demo.HQLexamples.

<query name="namedStudentHql"><![CDATA[ from Student s where s.studentName= :sname]]></query>

List namedHqlList = session.getNamedQuery("namedStudentHql").setString("sname", "Joseph Raj Kumar").list();
for(Object namedhql: whereList)
System.out.println("Student Id is "+ ((Student)namedhql).getId());

Named SQL:

Just as the HQL named queries, the SQL queries can also be named and retrieved by name in the same fashion.

<sql-query name="namedNativeStudentSQL"><![CDATA[select * from STUDENTS]]></sql-query>

List namedSqlList = session.getNamedQuery("namedNativeStudentSQL").list();
ite = nativeSqlList.iterator();
while(ite.hasNext()){
Object [] objects = (Object []) ite.next();
System.out.println("Student Id "+ objects[0]);
System.out.println("Student name "+ objects[1]);
}

Hibernate with Spring

Spring provides support for Hibernate mainly in two flavors. They are HibernateTemplate and HibernateDaoSupport. Let us look into both of them one by one. Let us go to the package com.demo.hibernateWithSpring and look into the files in that package.

HibernateTemplate:

HibernateTemplate provides an abstract layer over a Hibernate Session. It's main objective is to simplify the work of opening and closing hibernate sessions.

XML Spring configuration:

Look at the xml file SpringConfigurationForHibernate.xml

<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.hsqldb.jdbcDriver" />
<property name="url" value="jdbc:hsqldb:hsql://localhost" />
<property name="username" value="sa" />
<property name="password" value="" />
</bean>

<bean id="mySessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="configLocation">
<value>
classpath:hibernate.cfg.xml
</value>
</property>
<property name="mappingResources">
<list>
<value>com/demo/hibernateWithSpring/hibernateWithSpring.hbm.xml
</value>
</list>
</property>
</bean>

<bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate">
<property name="sessionFactory">
<ref bean="mySessionFactory" />
</property>
</bean>

<bean id="carDao" class="com.demo.hibernateWithSpring.CarHBTemplateDao">
<property name="hibernateTemplate">
<ref bean="hibernateTemplate" />
</property>
</bean>

* If we are mapping hibernate using XML mapping files then Spring's
LocalSessionFactoryBean provides a bean that will refer the mapping metadata from one or more of the xml mapping files.

* Hence
mySessionFactory takes a reference to the org.hibernate.SessionFactory.

* The dataSource property refers to any implementation of javax.sql.DataSource

* The
configLocation locates the location of the hibernate.cfg.xml. * mappingResources defines the list of one or more mapping files in the classpath. * The hibernateTemplate defines the instance of the class HibernateTemplate which is an abstract layer for the Hibernate Session.

* When the instance of the class CarHBTemplateDao is created from Spring xml, it will inject the reference to the HibernateTemplate into the CarHBTemplateDao object. Hence the hibernateTemplate defined in the CarHBTemplateDao class will actually provide methods to deal with the Hibernate session. (i.e) the session factory bean is wired into the HibernateTemplate and the HibernateTemplate is wired into the CarHBTemplateDao.

* In the example we have used the methods save(), load() and find() from the hibernateTemplate.

The DAO class:

public class CarHBTemplateDao {

private HibernateTemplate hibernateTemplate;

public void setHibernateTemplate(HibernateTemplate hibernateTemplate) {
this.hibernateTemplate = hibernateTemplate;
}
// remaining code ...
}

HibernateDaoSupport:

Spring offers a convenient DAO support class that enables us to directly wire a session factory bena into the DAO class. Actuallt HibernateDaoSupport creates a HibernaterTemplate for us to use. All we have to do is extending this HibernateDaoSupport class in our DAO classes as given below.


public class CarHBDaoSupportDao extends HibernateDaoSupport {

// remaining code ...
}

We don't have to deal with the hibernateTemplate any more. We can use the getHibernateTemplate() to access the same methods we accessed using hibernateTemplate. XML Spring Configuration: quot;com.demo.hibernateWithSpring.CarHBDaoSupportDao"> <property name="sessionFactory" ref="mySessionFactory" /> </bean> * when the instance of the CarHBDaoSupportDao class is created using Spring, we should inject the reference of sessionFactory into the DAO class as given above.

Execute the classes SpringWithHibernateTemplateExecutor.java and SpringWithHibernateDaoSupportExecutor.java from the package and verify the results by running the simple select query on the table CARS as follows.


Spring's support for Hibernate with Annotation:

Let us go to the package annotation.com.demo.hibernateWithSpring and execute the classes Spring_AnnotationHbTemplateExecutor.java and Spring_AnnotationHbDaoSupportExecutor.java

Things to look into:

* The annotated ORM class Friend.java
* The spring configuration file SpringForHibernateAnnotation.xml

@Entity
@Table(name="FRIENDS")
public class Friend {

@Id
@GeneratedValue
@Column(name="ID")
private long id;

@Column(name="FRIEND_NAME")
private String name;

@Column(name="AGE")
private int age;

//getter and setter methods
}

The Spring configuraton xml:

<bean id="mySessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="annotatedClasses">
<list> <value>annotation.com.demo.hibernateWithSpring.Friend</value>
</list>
</property>
<property name="configLocation">
<value>
classpath:hibernate.cfg.xml
</value>
</property>
</bean>

* If we are using the Hibernate with annotation, then spring provides sessionFactory instance using the AnnotationSessionFactoryBean.
* The annotatedClasses tag defines the list of annotated classes that are used for mapping hibernate.
* All the rest of the spring configurations remain the same as we used hibernate with xml mapping.

Execute the Spring_AnnotationHbTemplateExecutor.java and Spring_AnnotationHbDaoSupportExecutor.java classes and verify the results in the eclipse console and as well as in the HSQL DB manger by running a simple select query on the table FRIENDS as follows.

Many to Many Bidirectional association

Mapping using Hibernate XML mapping:

Let us go to the package com.demo.manyToManyBidirectional and execute the class ManyToManyBidirectionalExecutor.java.

Things to look into:

* The ORM classes Student.java and Course.java
* The xml mapping file manyToManyBidirectional.hbm.xml

ORM:

public class Student {

private long id;

private String studentName;

private Set courses = new HashSet();

//getter and setter methods
}


public class Course {

private long id;

private String courseName;

private Set students = new HashSet();

//getter and setter methods
}

* Note that both the entities have reference to each other (i.e) Student class has a reference to Course and Course class has reference to Student.

XML:

<hibernate-mapping>
<class name="com.demo.manyToManyBidirectional.Student" table="STUDENTS" lazy="false">
<id name="id" column="STUDENT_ID">
<generator class="native" />
</id>
<property name="studentName" column="STUDENT_NAME" />
<set name="courses" table="STUDENT_COURSE" lazy="false" cascade="save-update">
<key column="STUDENT_ID" not-null="true" />
<many-to-many class="com.demo.manyToManyBidirectional.Course"
column="COURSE_ID" />
</set>
</class>

<class name="com.demo.manyToManyBidirectional.Course" table="COURSES" lazy="false">
<id name="id" column="COURSE_ID">
<generator class="native" />
</id>
<property name="courseName" column="COURSE_NAME" />
<set name="students" table="STUDENT_COURSE" lazy="false" inverse="true">
<key column="COURSE_ID" not-null="true" />
<many-to-many class="com.demo.manyToManyBidirectional.Student"
column="STUDENT_ID" />
</set>
</class>
</hibernate-mapping>

* refers the to-many association and also declares the collection table.
* cascase declares that inserting the objects will be taken care by the Student entity.
* refers the foreign key column of the collection table.

* declares the many-to-many association.
* inverse="true" on the Course side indicates that it will not participate in updating the collection table STUDENT_COURSE and hence only from the Student side the collection table will be updated. Other wise if both sides try to update the collection table either duplicate rows will be inserted or any unique constraint will be violated.

Once the
ManyToManyBidirectionalExecutor.java is executed, verify the results in the eclipse console and in the HSQL DB manager by running simple select queries on the following tables STUDENTS, COURSES and STUDENT_COURSE as follows.




Mapping by Annotation:

Let us go to the package annotation.com.demo.manyToManyBidirectioinal and execute the class
ManyToManyAnnotationBidirectionalExecutor.java

Things to look into:

The annotated ORM classes Student.java and Course.java

@Entity(name="annotation.com.demo.manyToManyBidirectioinal.Student")
@Table(name="STUDENTS")
public class Student {

@Id
@GeneratedValue(strategy=GenerationType.AUTO)
@Column(name="STUDENT_ID")
private long id;

@Column(name="STUDENT_NAME")
private String studentName;

@ManyToMany(cascade=CascadeType.ALL,fetch=FetchType.EAGER)
@JoinTable(name="STUDENT_COURSE",joinColumns=@JoinColumn(name="STUDENT_ID"),inverseJoinColumns=@JoinColumn(name="COURSE_ID"))
private Set courses = new HashSet();

//getter and setter methods
}


@Entity(name="annotation.com.demo.manyToManyBidirectioinal.Course")
@Table(name="COURSES")
public class Course {

@Id
@GeneratedValue(strategy=GenerationType.AUTO)
@Column(name="COURSE_ID")
private long id;

@Column(name="COURSE_NAME")
private String courseName;

@ManyToMany(cascade=CascadeType.ALL,fetch=FetchType.EAGER)
@JoinTable(name="STUDENT_COURSE",joinColumns=@JoinColumn(name="COURSE_ID"),inverseJoinColumns=@JoinColumn(name="STUDENT_ID"))
private Set students = new HashSet();

//getter and setter methods
}



*
@ManyToMany declares the many-to-many association
*
cascase declares that inserting the objects will be taken care by the Student entity.
* @JoinTable refers the table where the collection values will be stored.
* @JoinColumn represents the foreign key column of the collection table.
* Note that both the classes have references to each other and the common collection table STUDENT_COURSE.


Once the ManyToManyAnnotationBidirectionalExecutor.java is executed , verify the results as mentioned above.

Many to Many unidirectional association

Mapping using Hibernate XML mapping:

Let us go the package com.demo.manyToManyUnidirectional and execute class ManyToManyUnidirectionalExecutor.java.

Things to look into:
* The ORM classes Student.java and Course.java
* The xml mapping file manyToManyUnidirectional.hbm.xml

ORM:


public class Student {

private long id;

private String studentName;

private Set courses = new HashSet();

//getter and setter methods
}

public class Course {

private long id;

private String courseName;

//getter and setter methods
}

* Note that only Student entity has the references to Course entity and the later entity does not have any reference to the former entity. Hence only a unidirectional navigation is possible.

XML:
<hibernate-mapping auto-import="false">

<class name="com.demo.manyToManyUnidirectional.Student" table="STUDENTS" lazy="false">
<id name="id" column="STUDENT_ID"> <generator class="native" /> </id>
<property name="studentName" column="STUDENT_NAME" />
<set name="courses" table="STUDENT_COURSE" lazy="false" cascade="save-update">
<
key column="STUDENT_ID" not-null="true" />
<
many-to-many class="com.demo.manyToManyUnidirectional.Course" column="COURSE_ID" />
</set>
</class>

<class name="com.demo.manyToManyUnidirectional.Course" table="COURSES" lazy="false">
<id name="id" column="COURSE_ID">
<generator class="native" /> </id>
<property name="courseName" column="COURSE_NAME" />
</class>

</hibernate-mapping>


* <set> refers the to-many association and also declares the collection table.
* cascase declares that inserting the objects will be taken care by the Student entity.
* <key> refers the foreign key column of the collection table.

* <many-to-many> declares the many-to-many association.


Once the ManyToManyUnidirectionalExecutor.java is executed, verify the results in the HSQL DB manager by executing the simple select queries on the tables STUDENTS, COURSES and STUDENT_COURSE as follows.





Mapped by Annotations:

Let us go to the package annotation.com.demo.manyToManyUnidirectional and execute the class ManyToManyAnnotationUniDirectionalExecutor.java

Things to look into:

The annotated ORM classes Student.java and Course.java

ORM:

@Entity(name="annotation.com.demo.manyToManyUnidirectional.Student")
@Table(name="STUDENTS")
public class Student {

@Id
@GeneratedValue(strategy=GenerationType.AUTO)
@Column(name="STUDENT_ID")
private long id;

@Column(name="STUDENT_NAME")
private String studentName;

@ManyToMany(cascade=CascadeType.ALL,fetch=FetchType.EAGER)
@JoinTable(name="STUDENT_COURSE",joinColumns=@JoinColumn(name="STUDENT_ID"),inverseJoinColumns=@JoinColumn(name="COURSE_ID"))
private Set courses = new HashSet();

//getter and setter methods
}

@Entity(name="annotation.com.demo.manyToManyUnidirectional.Course")
@Table(name="COURSES")
public class Course {

@Id
@GeneratedValue(strategy=GenerationType.AUTO)
@Column(name="COURSE_ID")
private long id;

@Column(name="COURSE_NAME")
private String courseName;

//getter and setter methods
}

*
@ManyToMany declares the many-to-many association
*
cascase declares that inserting the objects will be taken care by the Student entity.
* @JoinTable refers the table where the collection values will be stored.
* @JoinColumn represents the foreign key column of the collection table.

Once the
ManyToManyAnnotationUniDirectionalExecutor.java is executed , verify the results as mentioned above.

One to Many association using Join Table

Here in this example, the one to many association will be achieved by using a join table.

Mapping using Hibernate XML mapping:

Let us go to the package com.demo.oneToManyUsingJoinTable and execute the class OneToManyUsingJoinTableExecutor.java

Things to look into:

* The ORM classes Buyer.java and Property.java
* The xml mapping file oneToManyUsingJoinTable.hbm.xml

ORM:


public class Buyer {

private long id;

private String buyerName;

Set properties = new HashSet();

//getter and setter methods

}

public class Property {


private long id;

private String propertyName;

private String propertyValue; private Buyer buyer;

//getter and setter methods
}

* The Buyer class has a variable of type Collections
* Both the classes have a reference to each other and hence bidirectional.

XML:

<hibernate-mapping auto-import="false">
<class name="com.demo.oneToManyUsingJoinTable.Buyer" table="BUYER" lazy="false">
<id name="id" column="BUYER_ID">
<generator class="native" />
</id>
<property name="buyerName" column="BUYER_NAME" />
<set name="properties" table="PROPERTY_BUYER" cascade="save-update" lazy="false">
<key column="BUYER_ID" />
<many-to-many class="com.demo.oneToManyUsingJoinTable.Property"
column="PROPERTY_ID" unique="true" />
</set>
</class>
<class name="com.demo.oneToManyUsingJoinTable.Property" table="PROPERTY" lazy="false">
<id name="id" column="PROPERTY_ID">
<generator class="native" />
</id>
<property name="propertyName" column="PROPERTY_NAME" />
<property name="propertyValue" column="PROPERTY_VALUE" />
<join table="PROPERTY_BUYER" optional="true" inverse="true">
<key column="PROPERTY_ID" unique="true" not-null="true" />
<many-to-one name="buyer" column="BUYER_ID" />
</join>
</class>
</hibernate-mapping>

* <set> declares that it is holding the collection of objects and they are stored in a separate table PROPERTY_BUYER
* <key> represents the foreign key column of the collection table PROPERTY_BUYER
* Here, the tag <many-to-many> is used instead of the tag <one-to-many>. This is because, the one-to-many does not know anything about the join table and hence this is indirectly achieved by using the many-to-one along with the constraint unique="true". Now the association is still a one-to-many with the join table.
* The one side of the association takes care of inserting the objects into the database as cascade is defined on the one side of the association.
* On the other hand, the <join> declares the join table.
* option="true" represents that the data can not be inserted if the any of these mapping columns are null.
* inverse="true" represents that it many side of the association will not insert the data into database rather the non inverse side will do the job for it.
*<many-to-one> declares the many-to-one association.

Once the OneToManyUsingJoinTableExecutor.java is executed, verify the results in the eclipse console as well as in the HSQL DB manager by executing the simple select queries on the tables Buyer, Property and Property_Buyer as follows.




Mapping by Annotations:

Let us now go to the package annotation.com.demo.oneToManyUsingJoingTable and execute the class OneToManyJoinTableAnnotationExecutor.java

Things to look into:

* The annotated ORM classes Buyer.java and Property.java

@Entity
@Table(name="BUYER")
public class Buyer {

@Id
@GeneratedValue(strategy=GenerationType.AUTO)
@Column(name="BUYER_ID")
private long id;

@Column(name="BUYER_NAME")
private String buyerName;

@OneToMany(mappedBy="buyer",cascade=CascadeType.ALL,fetch=FetchType.EAGER)
Set properties = new HashSet();

//getter and setter methods
}


@Entity
@Table(name="PROPERTY")
public class Property {

@Id
@GeneratedValue(strategy=GenerationType.AUTO)
@Column(name="PROPERTY_ID")
private long id;

@Column(name="PROPERTY_NAME")
private String propertyName;

@Column(name="PROPERTY_VALUE")
private String propertyValue;

@ManyToOne(fetch=FetchType.EAGER)
@JoinTable(name="PROPERTY_BUYER",joinColumns=@JoinColumn(name="PROPERTY_ID"),inverseJoinColumns=@JoinColumn(name="BUYER_ID"))
private Buyer buyer;

//getter and setter methods
}

* @OneToMany represents the one-to-many association
* mappedBy="buyer" is the simple inverse declaration of an association, naming the property on the target entity side (i.e) on the Property side.
* @JoinTable refers the table where the collection values will be stored.
* @ManyToOne declares the many-to-one association.

Once the
OneToManyJoinTableAnnotationExecutor.java is executed verify the results as mentioned above.

One to Many Bidirectional association

In One to many bidirectional association, both sides of the association will have the reference to each other. The one side of the association will implement any one of the collection interfaces to refer the many references.

Mapping using Hibernate XML mapping:

Let us go to the package com.demo.oneToManyBidirectional and execute the class OneToManyBirectionalExecutor.java.

Things to look into:

* The ORM classes User.java and Account.java
* The xml mapping file oneToManyBidirectional.hbm.xml

ORM:

public class User {

private long id;

private String name;

private Set accounts = new HashSet();

// getter and setter methods
}

public class Account {

private long id;

private String accountType;

private User user;

// getter and setter methods
}

* Note that both the entity classes have the reference to each other and hence accomplishes the bidirectional navigation.

XML:

<hibernate-mapping auto-import="false">
<class name="com.demo.oneToManyBidirectional.User" table="USER"
lazy="false">
<id name="id" column="USER_ID">
<generator class="native" />
</id>
<property name="name" column="NAME" />
<set name="accounts" cascade="save-update">
<key column="USER_ID" not-null="true"/>
<one-to-many class="com.demo.oneToManyBidirectional.Account" />
</set>
</class>
<class name="com.demo.oneToManyBidirectional.Account" table="ACCOUNT"
lazy="false">
<id name="id" column="ACCOUNT_ID">
<generator class="native" />
</id>
<property name="accountType" column="ACCOUNT_TYPE" />
<many-to-one name="user" column="USER_ID"
class="com.demo.oneToManyBidirectional.User" not-null="true" insert="false" update="false"/>
</class>
</hibernate-mapping>

* This time the collection values are not stored in a separate table rather they are stored in the target table that is the Account table.
* We are supposed to make any one of the sides of the association as inverse and we intentionally choose to have the many side as inverse. (i.e) we want to store values from the one side and to store the state of the collections.
* As <many-to-one> does not have the inverse attribute, we make use of the insert="false" and update="false" in order to achieve the inverse="true".
* It is also possible to make the one side of the association as inverse and storing the values from the many side.

Once the class OneToManyBirectionalExecutor.java is executed , verify the results in the eclipse console and as well as in the HSQL DB manager by running simple select queries on the tables User and Account as follows.




Mapping using Annotations:

Let us go to the package annotation.com.demo.oneToManyBidirectional and execute the class OneToManyAnnotationBidirectionalExecutor.java

Things to look into:

* The annotated ORM classes User.java and Account.java

@Entity(name="annotation.com.demo.oneToManyBidirectional.User")
@Table(name="USER")
public class User {

@Id
@GeneratedValue(strategy=GenerationType.AUTO)
@Column(name="USER_ID")
private long id;

@Column(name="NAME")
private String name;

@OneToMany(cascade=CascadeType.ALL,fetch=FetchType.EAGER)
@JoinColumn(name="USER_ID",nullable=false)
private Set accounts = new HashSet();

// getter and setter methods
}


@Entity(name="annotation.com.demo.oneToManyBidirectional.Account")
@Table(name="ACCOUNT")
public class Account {

@Id
@GeneratedValue(strategy=GenerationType.AUTO)
@Column(name="ACCOUNT_ID")
private long id;

@Column(name="ACCOUNT_TYPE")
private String accountType;

@ManyToOne(fetch=FetchType.EAGER)
@JoinColumn(name="USER_ID",nullable=false,updatable=false,insertable=false)
private User user;

//getter and setter methods
}


*
@OneToMany represents the one-to-many association.
*
@ManyToOne represents the many-to-one association.
*
@JoinColumn refer the foreign key column in the Account table
* updatable=false and insertable=false specify that the many side of the assiciation will participate in the insert or update activities.

Once the OneToManyAnnotationBidirectionalExecutor.java is executed verify the results as mentioned above.