Map Mapping
Map map is a java collection that stores elements in key-value pairs and does not allow duplicate elements in a list. The Map interface provides three collection views, allowing the Map content to be regarded as a set of key-value collections, or setting the key-value mapping relationship.
Map is mapped to a <map> element in the mapping table and an unordered map can be initialized in java.util.HashMap.
Define RDBMS table:
Consider a situation where we need employee records to be stored in the EMPLOYEE table, which will have the following structure:
create table EMPLOYEE ( id INT NOT NULL auto_increment, first_name VARCHAR(20) default NULL, last_name VARCHAR(20) default NULL, salary INT default NULL, PRIMARY KEY (id));
Furthermore, it is assumed that each employee can have one or more certificates related to him/her. We store the relevant information of the certificate in a separate table with the following structure:
create table CERTIFICATE ( id INT NOT NULL auto_increment, certificate_type VARCHAR(40) default NULL, certificate_name VARCHAR(30) default NULL, employee_id INT default NULL, PRIMARY KEY (id));
There is a one-to-many relationship between EMPLOYEE and the certificate object.
Define POJO class:
Let's implement a POJO class employee that will be used to hold a collection of objects in the EMPLOYEE table and a list variable with certificates.
import java.util.*;public class Employee { private int id; private String firstName; private String lastName; private int salary; private Map certificates; public Employee() {} public Employee(String fname, String lname, int salary) { this.firstName = fname; this.lastName = lname; this.salary = salary; } public int getId() { return id; } public void setId( int id ) { this.id = id; } public String getFirstName() { return firstName; } public void setFirstName( String first_name ) { this.firstName = first_name; } public String getLastName() { return lastName; } public void setLastName( String last_name ) { this.lastName = last_name; } public int getSalary() { return salary; } public void setSalary( int salary ) { this.salary = salary; } public Map getCertificates() { return certificates; } public void setCertificates( Map certificates ) { this.certificates = certificates; }}We need the corresponding certificate table to define another POJO class, such a certificate object can store and retrieve the certificate table.
public class Certificate{ private int id; private String name; public Certificate() {} public Certificate(String name) { this.name = name; } public int getId() { return id; } public void setId( int id ) { this.id = id; } public String getName() { return name; } public void setName( String name ) { this.name = name; }} Define Hibernate mapping file:
Let's develop a mapping file that instructs Hibernate how to define a class mapped to a database table. The <map> element will be used to define the rules for the map used.
<?xml version="1.0" encoding="utf-8"?><!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <class name="Employee" table="EMPLOYEE"> <meta attribute="class-description"> This class contains the employee detail. </meta> <id name="id" type="int" column="id"> <generator/> </id> <map name="certificates" cascade="all"> <key column="employee_id"/> <index column="certificate_type" type="string"/> <one-to-many/> </map> <property name="firstName" column="first_name" type="string"/> <property name="lastName" column="last_name" type="string"/> <property name="salary" column="salary" type="int"/> </class> <class name="Certificate" table="CERTIFICATE"> <meta attribute="class-description"> This class contains the certificate records. </meta> <id name="id" type="int" column="id"> <generator/> </id> <property name="name" column="certificate_name" type="string"/> </class></hibernate-mapping>
The format <classname>.hbm.xml in the mapping file that should be saved. We save the file Employee.hbm.xml in the mapping file. Already familiar with most of the mapping details, but let's look at all the elements in the mapping file again:
A mapped document is an XML document with <hibernate-mapping> as a root element corresponding to each class containing 2 <class> elements.
The <class> element is used to define a database table specific mapping from a Java class. Java class name specifies the name attribute of the class element and the table attribute database table name specifies.
The <meta> element is an optional element that can be used to create a description of the class.
The <id> element maps the unique ID attribute in the class to the primary key of the database table. The name attribute of the id element refers to the class of the attribute and the column attribute refers to the columns in the database table. The type attribute saves the Hibernate mapping type, which will be converted from Java to SQL data type.
The <generator> element within the id element is used to automatically generate the primary key value. Set the class attribute of the generated element to be native to let Hibernate pick up the algorithm in either identity, sequence, or hilo to create primary keys according to the support capabilities of the underlying database.
The <property> element is used to map properties of a Java class to columns in a database table. The name attribute of an element refers to the class of the attribute and the column attribute refers to the columns in the database table. The type attribute saves the Hibernate mapping type, which will be converted from Java to SQL data type.
The <map> element is used to set the relationship between the certificate and the Employee class. We use the <map> element of the cascade attribute to tell Hibernate to save the certificate object, and also to the Employee object. The name attribute is set to define the Mapvariable in the parent class, in our case the certificate.
The <index> element is used to represent key/value pairs of keys and values. This key will use a string type stored in the column certificate_type.
The <key> element is the parent object containing a foreign key, that is, the column in the certificate table. Table EMPLOYEE.
The <one-to-many> element indicates that an Employee object involves many certificate objects, and therefore, the certificate object must be related to the Employee parent class. You can use the elements <one-to-one>, <many-to-one> or <many-to-many> as needed.
Create an application class:
Finally, create the main() method of the application class to run the application. Use this application to save employee records along with the certificate list, and then perform records on the CRUD operation on the application.
import java.util.*; import org.hibernate.HibernateException; import org.hibernate.Session; import org.hibernate.Transaction;import org.hibernate.SessionFactory;import org.hibernate.cfg.Configuration;public class ManageEmployee { private static SessionFactory factory; public static void main(String[] args) { try{ factory = new Configuration().configure().buildSessionFactory(); }catch (Throwable ex) { System.err.println("Failed to create sessionFactory object." + ex); throw new ExceptionInInitializerError(ex); } ManageEmployee ME = new ManageEmployee(); /* Let us have a set of certificates for the first employee */ HashMap set = new HashMap(); set.put("ComputerScience", new Certificate("MCA")); set.put("BusinessManagement", new Certificate("MBA")); set.put("ProjectManagement", new Certificate("PMP")); /* Add employee records in the database */ Integer empID = ME.addEmployee("Manoj", "Kumar", 4000, set); /* List down all the employees */ ME.listEmployee(); /* Update employee's salary records */ ME.updateEmployee(empID, 5000); /* List down all the employees */ ME.listEmployees(); } /* Method to add an employee record in the database */ public Integer addEmployee(String fname, String lname, int salary, HashMap cert){ Session session = factory.openSession(); Transaction tx = null; Integer employeeID = null; try{ tx = session.beginTransaction(); Employee employee = new Employee(fname, lname, salary); employee.setCertificates(cert); employeeID = (Integer) session.save(employee); tx.commit(); }catch (HibernateException e) { if (tx!=null) tx.rollback(); e.printStackTrace(); } finally { session.close(); } return employeeID; } /* Method to list all the employees details */ public void listEmployees( ){ Session session = factory.openSession(); Transaction tx = null; try{ tx = session.beginTransaction(); List employees = session.createQuery("FROM Employee").list(); for (Iterator iterator1 = employees.iterator(); iterator1.hasNext();){ Employee employee = (Employee) iterator1.next(); System.out.print("First Name: " + employee.getFirstName()); System.out.print(" Last Name: " + employee.getLastName()); System.out.println(" Salary: " + employee.getSalary()); Map ec = employee.getCertificates(); System.out.println("Certificate: " + ((((Certificate)ec.get("ComputerScience")).getName())); System.out.println("Certificate: " + ((((Certificate)ec.get("BusinessManagement")).getName())); System.out.println("Certificate: " + ((((Certificate)ec.get("ProjectManagement")).getName())); System.out.println("Certificate: " + ((((Certificate)ec.get("ProjectManagement")).getName())); } tx.commit(); }catch (HibernateException e) { if (tx!=null) tx.rollback(); e.printStackTrace(); } finally { session.close(); } } /* Method to update salary for an employee */ public void updateEmployee(Integer EmployeeID, int salary ){ Session session = factory.openSession(); Transaction tx = null; try{ tx = session.beginTransaction(); Employee employee = (Employee)session.get(Employee.class, EmployeeID); employee.setSalary( salary ); session.update(employee); tx.commit(); }catch (HibernateException e) { if (tx!=null) tx.rollback(); e.printStackTrace(); } finally { session.close(); } } /* Method to delete an employee from the records */ public void deleteEmployee(Integer EmployeeID){ Session session = factory.openSession(); Transaction tx = null; try{ tx = session.beginTransaction(); Employee employee employee = (Employee)session.get(Employee.class, EmployeeID); session.delete(employee); tx.commit(); }catch (HibernateException e) { if (tx!=null) tx.rollback(); e.printStackTrace(); } finally { session.close(); } }} Compile and execute:
Here are the steps to compile and run the above application. Please make sure that you have set PATH and CLASSPATH appropriately before compiling and executing.
The following results will be obtained on the screen and records are created in both the employee and certificate forms.
$java ManageEmployee
.....VARIOUS LOG MESSAGES WILL DISPLAY HERE.........
First Name: Manoj Last Name: Kumar Salary: 4000Certificate: MCACertificate: MBACertificate: PMPFirst Name: Manoj Last Name: Kumar Salary: 5000Certificate: MCACertificate: MBACertificate: PMP
If you check the employee and certificate form, you should record it:
mysql> select * from EMPLOYEE;
+-----------------------------+------------+| id | first_name | last_name | salary |+--------------------------------------+---------------+| 60 | Manoj | Kumar | 5000 |+---------------------------------+---------+1 row in set (0.00 sec)
mysql>select * from CERTIFICATE;
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
SortedMap Mapping
SortedMap is an element stored in a key-value pair and provides the overall sort of keys similar to Java collections for mappings. Duplicate elements are not allowed in the mapping. The map is sorted in the natural order of its keys, or by providing a comparison usually at the creation time of the ordered map.
The <map> elements and ordered maps that SortedMap are mapped in the mapping table can be initialized in java.util.TreeMap.
We still use the RDBMS table and POJO class defined above to illustrate the following example:
Define Hibernate mapping file:
Let's develop a mapping file that instructs Hibernate how to define a class mapped to a database table. The <map> element will be used to define the rules for the map used.
<?xml version="1.0" encoding="utf-8"?><!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <class name="Employee" table="EMPLOYEE"> <meta attribute="class-description"> This class contains the employee detail. </meta> <id name="id" type="int" column="id"> <generator/> </id> <map name="certificates" cascade="all" sort="MyClass"> <key column="employee_id"/> <index column="certificate_type" type="string"/> <one-to-many/> </map> <property name="firstName" column="first_name" type="string"/> <property name="lastName" column="last_name" type="string"/> <property name="salary" column="salary" type="int"/> </class> <class name="Certificate" table="CERTIFICATE"> <meta attribute="class-description"> This class contains the certificate records. </meta> <id name="id" type="int" column="id"> <generator/> </id> <property name="name" column="certificate_name" type="string"/> </class></hibernate-mapping>
The format <classname>.hbm.xml in the mapping file that should be saved. We save the mapping file Employee.hbm.xml. Already familiar with most of the mapping details, but let's look at all the elements in the mapping file again:
A mapped document is an XML document with a root element of <hibernate-mapping> corresponding to each class containing 2 <class> elements.
The <class> element is used to define a database table specific mapping from a Java class. Java class name specifies the name attribute of the class element and the table attribute database table name specifies.
The <meta> element is an optional element that can be used to create a description of the class.
The <id> element maps the unique ID attribute in the class to the primary key of the database table. The name attribute of the id element refers to the class of the attribute and the column attribute refers to the columns in the database table. The type attribute saves the Hibernate mapping type, which will be converted from Java to SQL data type.
The <generator> element within the id element is used to automatically generate the primary key value. Set the class attribute of the generated element to make Hibernate corresponding to the algorithm in identity, sequence or hilo to create primary keys according to the support capabilities of the underlying database.
The <property> element is used to map properties of a Java class to columns in a database table. The name attribute of an element refers to the class of the attribute and the column attribute refers to the columns in the database table. The type attribute saves the Hibernate mapping type, which will be converted from Java to SQL data type.
The <map> element is used to set the relationship between the certificate and the Employee class. We use the <map> element of the cascade attribute to tell Hibernate to save the certificate object, and also to the Employee object. The name attribute is set to the SortedMap variable defined in the parent class, in our case it is a certificate. The sorting property can be set to natural sorting, or it can be set to custom class implementation as java.util.Comparator. We have used a class MyClass that implements it as java.util.Comparator to reverse the sort order of the certificate class implementation.
The <index> element is used to represent the key part of the key/value pair map. This key will use a string type stored in the column certificate_type.
The <key> element is the parent object containing a foreign key, that is, the column in the certificate table. Table EMPLOYEE.
The <one-to-many> element indicates that an Employee object involves many certificate objects, and therefore, the certificate object must be associated with the Employee parent. You can use the elements <one-to-one>, <many-to-one> or <many-to-many> as needed.
If you use sort="natural", then we don't need to create a separate class, because the certificate class has implemented the Comparable interface and hibernate will use compareTo in the certificate class defined as the SortedMap() method. However, we are using a custom comparator class MyClass in our mapping file, so we have to create this class based on our sorting algorithm. Let's do the key sorting that is available on the map.
import java.util.Comparator;public class MyClass implements Comparator <String>{ public int compare(String o1, String o2) { final int BEFORE = -1; final int AFTER = 1; /* To reverse the sorting order, multiple by -1 */ if (o2 == null) { return BEFORE * -1; } Comparable thisCertificate = o1; Comparable thatCertificate = o2; if(thisCertificate == null) { return AFTER * 1; } else if(thatCertificate == null) { return BEFORE * -1; } else { return thisCertificate.compareTo(thatCertificate) * -1; } }}Finally, we will create the main() method of the application class to run the application. We will use this application to save some employee records along with the certificate, and then we will submit the CRUD operation above the records.
import java.util.*; import org.hibernate.HibernateException; import org.hibernate.Session; import org.hibernate.Transaction;import org.hibernate.SessionFactory;import org.hibernate.cfg.Configuration;public class ManageEmployee { private static SessionFactory factory; public static void main(String[] args) { try{ factory = new Configuration().configure().buildSessionFactory(); }catch (Throwable ex) { System.err.println("Failed to create sessionFactory object." + ex); throw new ExceptionInInitializerError(ex); } ManageEmployee ME = new ManageEmployee(); /* Let us have a set of certificates for the first employee */ TreeMap set1 = new TreeMap(); set1.put("ComputerScience", new Certificate("MCA")); set1.put("BusinessManagement", new Certificate("MBA")); set1.put("ProjectManagement", new Certificate("PMP")); /* Add employee records in the database */ Integer empID1 = ME.addEmployee("Manoj", "Kumar", 4000, set1); /* Another set of certificates for the second employee */ TreeMap set2 = new TreeMap(); set2.put("ComputerScience", new Certificate("MCA")); set2.put("BusinessManagement", new Certificate("MBA")); /* Add another employee record in the database */ Integer empID2 = ME.addEmployee("Dilip", "Kumar", 3000, set2); /* List down all the employees */ ME.listEmployee(); /* Update employee's salary records */ ME.updateEmployee(empID1, 5000); /* Delete an employee from the database */ ME.deleteEmployee(empID2); /* List down all the employees */ ME.listEmployees(); } /* Method to add an employee record in the database */ public Integer addEmployee(String fname, String lname, int salary, TreeMap cert){ Session session = factory.openSession(); Transaction tx = null; Integer employeeID = null; try{ tx = session.beginTransaction(); Employee employee = new Employee(fname, lname, salary); employee.setCertificates(cert); employeeID = (Integer) session.save(employee); tx.commit(); }catch (HibernateException e) { if (tx!=null) tx.rollback(); e.printStackTrace(); } finally { session.close(); } return employeeID; } /* Method to list all the employees details */ public void listEmployees( ){ Session session = factory.openSession(); Transaction tx = null; try{ tx = session.beginTransaction(); List employees = session.createQuery("FROM Employee").list(); for (Iterator iterator1 = employees.iterator(); iterator1.hasNext();){ Employee employee = (Employee) iterator1.next(); System.out.print("First Name: " + employee.getFirstName()); System.out.print("Last Name: " + employee.getLastName()); System.out.println(" Salary: " + employee.getSalary()); SortedMap<String, Certificate> map = employee.getCertificates(); for(Map.Entry<String, Certificate> entry : map.entrySet()){ System.out.print("/tCertificate Type: " + entry.getKey()); System.out.println(", Name: " + (entry.getValue()).getName()); } } tx.commit(); }catch (HibernateException e) { if (tx!=null) tx.rollback(); e.printStackTrace(); } finally { session.close(); } } /* Method to update salary for an employee */ public void updateEmployee(Integer EmployeeID, int salary ){ Session session = factory.openSession(); Transaction tx = null; try{ tx = session.beginTransaction(); Employee employee = (Employee)session.get(Employee.class, EmployeeID); employee.setSalary( salary ); session.update(employee); tx.commit(); }catch (HibernateException e) { if (tx!=null) tx.rollback(); e.printStackTrace(); } finally { session.close(); } } /* Method to delete an employee from the records */ public void deleteEmployee(Integer EmployeeID){ Session session = factory.openSession(); Transaction tx = null; try{ tx = session.beginTransaction(); Employee employee employee = (Employee)session.get(Employee.class, EmployeeID); session.delete(employee); tx.commit(); }catch (HibernateException e) { if (tx!=null) tx.rollback(); e.printStackTrace(); } finally { session.close(); } }} Compile and execute:
You can see that the certificates have been sorted in the opposite order. You can try it by changing the mapping file, just set sort="natural" and execute the program, and compare the results.
$java ManageEmployee
.....VARIOUS LOG MESSAGES WILL DISPLAY HERE.........First Name: Manoj Last Name: Kumar Salary: 4000 Certificate Type: ProjectManagement, Name: PMP Certificate Type: ComputerScience, Name: MCA Certificate Type: BusinessManagement, Name: MBAFirst Name: Dilip Last Name: Kumar Salary: 3000 Certificate Type: ComputerScience, Name: MCA Certificate Type: BusinessManagement, Name: MBAFirst Name: Manoj Last Name: Kumar Salary: 5000 Certificate Type: ProjectManagement, Name: PMP Certificate Type: ComputerScience, Name: MCA Certificate Type: BusinessManagement, Name: MBA
If you check the employee and certificate form, you should record it:
mysql> select * from EMPLOYEE;
+----+--------------------+---------+| id | first_name | last_name | salary |+------------------------------------+-------------+------------+| 74 | Manoj | Kumar | 5000 |+--------------------------------+---------+1 row in set (0.00 sec)
mysql> select * from CERTIFICATE;
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------