In this post I am trying to add a reference mapping project which includes most of the real world scenarios you will encounter when using hibernate.This example is primarily meant for differentiating the various types of relationships in hibernate and it is tested for the SAVE, UPDATE and SELECT features. I leave it to you to find out how to DELETE a row in the table or a member in the child list.
If you are not familiar with the hibernate get an heads up on the various object relations in from this article.
Now lets take an example and try to put a Object map and table design for the same. I am trying to provide all the relations in the same example.
As first step create the java and hibernate files as below.
1. AMain.java
package com.manu.hibernate.mappings.domain;
import java.util.List;
import java.util.Set;
/**
* The Main class A.
*/
public class AMain {
//Properties of A.
Integer aId;
String name;
String prop1;
String prop2;
ASub1 one2oneSubA1;
Set<ASub2> subSets;
List<ASub3> subList;
RefOnlyAMain one2oneSubRef;
public AMain(String name) {
this.name = name;
}
public AMain() {
}
/* Add the Getters and Setters */
@Override
public String toString() {
// TODO Auto-generated method stub
return " AMain with Id:"+aId+" Name:"+name;
}
}
2. ASub1.java
package com.manu.hibernate.mappings.domain;
public class ASub1 {
Integer as1Id;
Integer aId;
String subName;
AMain parent;
public ASub1(String subName) {
this.subName = subName;
}
public ASub1() {
}
/* Add the Getters and Setters */
@Override
public String toString() {
return " ASub1 with Id:"+as1Id+" Name:"+subName+" Parent:"+parent;
}
}
3. Similarly create the classes ASub2.java, ASub3.java, RefOnlyAMain.java
4. The Mapping file ABeanTypes.hbm.xml
Note:- It is better to move the xml declaration to separate files I have put them together for easy understanding.
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.manu.hibernate.mappings.domain">
<class name="AMain" table="A_Main">
<id name="aId" column="a_id" unsaved-value="null">
<generator class="hilo" />
</id>
<property name="name" />
<property name="prop1" />
<property name="prop2" />
<one-to-one name="one2oneSubA1" class="com.manu.hibernate.mappings.domain.ASub1" cascade="all"
property-ref="parent"/>
<set name="subSets" inverse="true" cascade="all">
<key column="a_id" />
<one-to-many class="com.manu.hibernate.mappings.domain.ASub2" />
</set>
<list name="subList" inverse="true" cascade="all" lazy="false">
<key column="a_id" />
<list-index column="as3_id" />
<one-to-many class="com.manu.hibernate.mappings.domain.ASub3" />
</list>
<one-to-one name="one2oneSubRef"
class="com.manu.hibernate.mappings.domain.RefOnlyAMain" property-ref="parentARef"
cascade="all" >
<formula>'A'</formula>
<formula>a_id</formula>
</one-to-one>
</class>
<class name="ASub1" table="A_Sub1">
<id name="as1Id" column="as1_id" unsaved-value="null">
<generator class="hilo" />
</id>
<property name="subName" column="sub_name" />
<property name="aId" column="a_id" insert="false" update="false" />
<many-to-one name="parent"
class="com.manu.hibernate.mappings.domain.AMain" column="a_id"
unique="true" cascade="save-update" />
</class>
<class name="ASub2" table="A_Sub2">
<id name="as2Id" column="as2_id" unsaved-value="null">
<generator class="hilo" />
</id>
<property name="subName" column="sub_name" />
<property name="aId" column="a_id" insert="false" update="false" />
<many-to-one class="com.manu.hibernate.mappings.domain.AMain"
name="parent" column="a_id" />
</class>
<class name="ASub3" table="A_Sub3">
<id name="as3Id" column="as3_id" unsaved-value="null">
<generator class="hilo" />
</id>
<property name="subName" column="sub_name" />
<property name="aId" column="a_id" insert="false" update="false" />
<many-to-one class="com.manu.hibernate.mappings.domain.AMain"
name="parent" column="a_id" />
</class>
<class name="RefOnlyAMain" table="Ref_A_Main">
<id name="refId" column="ref_id" unsaved-value="null">
<generator class="hilo" />
</id>
<property name="name" />
<property name="aOrbId" column="aOrb_id" insert="false" update="false" />
<property name="aOrbInd" column="aOrb_ind" />
<properties name="parentARef">
<property name="aOrbInd" column="aOrb_ind" insert="false" update="false"/>
<many-to-one name="parentA"
class="com.manu.hibernate.mappings.domain.AMain" column="aOrb_id"
unique="true" cascade="save-update" />
</properties>
</class>
</hibernate-mapping>
5.The hibernate configuration file.
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/appDB1</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">manupk</property>
<property name="hibernate.connection.pool_size">10</property>
<property name="show_sql">true</property>
<property name="dialect">org.hibernate.dialect.MySQLDialect</property>
<property name="hibernate.hbm2ddl.auto">create</property>
<mapping resource="com\manu\hibernate\mappings\domain\ABeanTypes.hbm.xml" />
</session-factory>
</hibernate-configuration>
6. Test client.
package com.manu.hibernate.mappings.client;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import com.manu.hibernate.mappings.domain.AMain;
import com.manu.hibernate.mappings.domain.ASub1;
import com.manu.hibernate.mappings.domain.ASub2;
import com.manu.hibernate.mappings.domain.ASub3;
import com.manu.hibernate.mappings.domain.RefOnlyAMain;
/**
* @author Manupk
*
*/
public class RelationsSaveTest {
/**
* @param args
*/
public static void main(String[] args) {
SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory();
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
//Create the Parent Object.
AMain a = new AMain("A");
//One2One Child of AMain, with shared column in both table.
ASub1 as1 = new ASub1("ASub - 1");
as1.setParent(a);
a.setOne2oneSubA1(as1);
//One2Many Using set, with shared column in both table.
ASub2 as2a = new ASub2("Set - 1");
ASub2 as2b = new ASub2("Set - 2");
as2a.setParent(a);
as2b.setParent(a);
Set<ASub2> subSet = new HashSet<ASub2>();
subSet.add(as2a);
subSet.add(as2b);
a.setSubSets(subSet);
//One2Many using List, with shared column in both table.
ASub3 as3a = new ASub3("List - 1");
ASub3 as3b = new ASub3("List - 2");
ASub3 as3c = new ASub3("List - 3");
as3a.setParent(a);
as3b.setParent(a);
as3c.setParent(a);
List<ASub3> subList = new ArrayList<ASub3>();
subList.add(as3a);
subList.add(as3b);
subList.add(as3c);
a.setSubList(subList);
//One2One Child of AMain, but without a shared column.
RefOnlyAMain rfa = new RefOnlyAMain();
rfa.setaOrbInd("A"); //Add the indicator to point the correct parent class.
rfa.setName("Child 1 A");
rfa.setParentA(a);
a.setOne2oneSubRef(rfa);
session.save(a);
session.flush();
tx.commit();
session.close();
//Close the session and open a new one for proper testing.
session =sessionFactory.openSession();
List<AMain> result1 = session.createQuery(" from AMain").list();
System.out.println(result1);
List<ASub1> result2 = session.createQuery(" from ASub1 ").list();
System.out.println(result2);
List<ASub2> result3 = session.createQuery(" from ASub2").list();
System.out.println(result3);
List<ASub3> result4 = session.createQuery(" from ASub3").list();
System.out.println(result4);
List<RefOnlyAMain> result6 = session.createQuery(" from RefOnlyAMain").list();
System.out.println(result6);
}
}
In the class AMain.java; note the properties,
ASub1 one2oneSubA1;
Set<ASub2> subSets;
List<ASub3> subList;
RefOnlyAMain one2oneSubRef;
As the name implies,
ASub1 has a One-to-One relationship with AMain.
ASub2 has a Many-to-One relationship with AMain and it is implemented using Set.
ASub3 has a Many-to-One relationship with AMain and it is implemented using List.
RefOnlyAMain a One-to-One relationship with AMain, but it does not share a column with AMain as in the above case.So we need to use the 'formula' to map this bean.
All the tables that contains the child data of AMain has the a_id column as the foreign key and all the mappings are done based on that.
Now have look at the test client.
In the test client all the properties are set and are being saved to the table.
All the table mappings are given in the ABeanType.hbm.xml file and are self explanatory.
When the Test client is executed the hibernate generates the insert scripts as below.
Note:- In the hibernate.cfg.xml file the property hibernate.hbm2ddl.auto is set as create so that hibernate automatically create the required table. Change it to update in the consecutive runs.
Hibernate automatically takes care about the referential integrity of data by inserting them in the order. All you need to do is to save the Main bean and all the child beans are automatically saved to the DB.If there is any error in the operation all the data inserts are rolled back and hibernate maintains the integrity of the data.
Hibernate: insert into A_Main (name, prop1, prop2, a_id) values (?, ?, ?, ?)
Hibernate: insert into A_Sub1 (sub_name, a_id, as1_id) values (?, ?, ?)
Hibernate: insert into A_Sub2 (sub_name, a_id, as2_id) values (?, ?, ?)
Hibernate: insert into A_Sub2 (sub_name, a_id, as2_id) values (?, ?, ?)
Hibernate: insert into A_Sub3 (sub_name, a_id, as3_id) values (?, ?, ?)
Hibernate: insert into A_Sub3 (sub_name, a_id, as3_id) values (?, ?, ?)
Hibernate: insert into A_Sub3 (sub_name, a_id, as3_id) values (?, ?, ?)
Hibernate: insert into Ref_A_Main (name, aOrb_ind, aOrb_id, ref_id) values (?, ?, ?, ?)
Hibernate: select amain0_.a_id as a1_1_, amain0_.name as name1_, amain0_.prop1 as prop3_1_, amain0_.prop2 as prop4_1_, 'A' as formula0_, amain0_.a_id as formula1_ from A_Main amain0_
Hibernate: select asub1x0_.as1_id as as1_2_0_, asub1x0_.sub_name as sub2_2_0_, asub1x0_.a_id as a3_2_0_ from A_Sub1 asub1x0_ where asub1x0_.a_id=?
Hibernate: select refonlyama0_.ref_id as ref1_5_0_, refonlyama0_.name as name5_0_, refonlyama0_.aOrb_id as aOrb3_5_0_, refonlyama0_.aOrb_ind as aOrb4_5_0_ from Ref_A_Main refonlyama0_ where refonlyama0_.aOrb_ind=? and refonlyama0_.aOrb_id=?
[ AMain with Id:1 Name:A]
Hibernate: select asub1x0_.as1_id as as1_2_, asub1x0_.sub_name as sub2_2_, asub1x0_.a_id as a3_2_ from A_Sub1 asub1x0_
[ ASub1 with Id:32768 Name:ASub - 1 Parent: AMain with Id:1 Name:A]
Hibernate: select asub2x0_.as2_id as as1_3_, asub2x0_.sub_name as sub2_3_, asub2x0_.a_id as a3_3_ from A_Sub2 asub2x0_
[ ASub2 with Id:65536 Name:Set - 2 Parent: AMain with Id:1 Name:A, ASub2 with Id:65537 Name:Set - 1 Parent: AMain with Id:1 Name:A]
Hibernate: select asub3x0_.as3_id as as1_4_, asub3x0_.sub_name as sub2_4_, asub3x0_.a_id as a3_4_ from A_Sub3 asub3x0_
[ ASub3 with Id:98304 Name:List - 1 Parent: AMain with Id:1 Name:A, ASub3 with Id:98305 Name:List - 2 Parent: AMain with Id:1 Name:A, ASub3 with Id:98306 Name:List - 3 Parent: AMain with Id:1 Name:A]
Hibernate: select refonlyama0_.ref_id as ref1_5_, refonlyama0_.name as name5_, refonlyama0_.aOrb_id as aOrb3_5_, refonlyama0_.aOrb_ind as aOrb4_5_ from Ref_A_Main refonlyama0_
[ RefOnlyAMain with Id:131072 Name:Child 1 A Parent: AMain with Id:1 Name:A]
Now go ahead and play around changing the values and table structure for better understanding.
Given below the code snippet used to update the set of child beans.
SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory();
Session session =sessionFactory.openSession();
Transaction tx = session.beginTransaction();
List<AMain> result1 = session.createQuery(" from AMain").list();
System.out.println(result1);
//Create the Parent Object.
AMain a = result1.get(0);
//One2One Child of AMain, with shared column in both table.
ASub1 as1 = a.getOne2oneSubA1();
as1.setSubName("NEW");
//One2Many using List, with shared column in both table.
ASub3 as3a = new ASub3("NEW List - 1");
ASub3 as3b = new ASub3("NEW List - 2");
ASub3 as3c = new ASub3("NEW List - 3");
as3a.setParent(a);
as3b.setParent(a);
as3c.setParent(a);
List<ASub3> subList = new ArrayList<ASub3>();
subList.add(as3a);
subList.add(as3b);
subList.add(as3c);
subList.addAll(a.getSubList());
a.setSubList(subList);
//session.createQuery("delete from ASub3").executeUpdate();
tx.commit();
session.close();
//Close the session and open a new one for proper testing.
session =sessionFactory.openSession();
Transaction tx2 = session.beginTransaction();
session.save(a);
session.flush();
tx2.commit();
session.close();