Introduction
A SortedSet is a java collection that contains no duplicate elements and is ordered by their natural ordering or by a comparator.
A SortedSet is mapped in the mapping table with an <set> element and initialized with java.util.TreeSet. A comparator or natural ordering can be specified as the sort attribute. Iterator traverses the set in ascending element order if we use natural ordering.
Hibernate SortedSet Mapping Procedure
Define RDBMS Tables
Consider the following scenario for the hibernate SortedSet mapping:
We need to store employee records in the EMPLOYEE table, which will have the following structure:
create table EMPLOYEE (id INT NOT NULL,
first_name VARCHAR(30),
last_name VARCHAR(30),
salary INT,
PRIMARY KEY (id)
);
Assume that each employee can be associated with one or more certificates. A collection table index column is required for a SortedSet collection mapping. As a result, we will store certificate information in a separate table with the following structure:
create table CERTIFICATE (
id INT NOT NULL,
name VARCHAR(30),
index INT,
employee_id INT,
PRIMARY KEY (id)
);
EMPLOYEE and CERTIFICATE objects will have a one-to-many relationship.
Define POJO Classes
The next step in hibernate sortedSet mapping is defining POJO classes.
Let us create a POJO class Employee that will be used to persist objects related to the EMPLOYEE table and a collection of certificates in the SortedSet variable.
import java.util.*;
public class Employee {
private int id;
private String firstName;
private String lastName;
private int salary;
private SortedSet certificates;
public Employee() {}
public Employee(String firstName, String lastName, int salary) {
this.firstName = firstName;
this.lastName = lastName;
this.salary = salary;
}
public void setId( int id ) {
this.id = id;
}
public int getId() {
return id;
}
public void setFirstName( String first_name ) {
this.firstName = first_name;
}
public String getFirstName() {
return firstName;
}
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 SortedSet getCertificates() {
return certificates;
}
public void setCertificates( SortedSet certificates ) {
this.certificates = certificates;
}
}
Let us now define another POJO class corresponding to the CERTIFICATE table so that certificate objects can be stored and retrieved from it. This class also implements the Comparable interface and the compareTo method, which will be used to sort the elements if sort="natural" is specified in your mapping file (see below mapping file) −
public class Certificate implements Comparable <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;
}
public int compareTo(Certificate that){
final int BEFORE = -1;
final int AFTER = 1;
if (that == null) {
return BEFORE;
}
Comparable thisCertificate = this.getName();
Comparable thatCertificate = that.getName();
if(thisCertificate == null) {
return AFTER;
} else if(thatCertificate == null) {
return BEFORE;
} else {
return thisCertificate.compareTo(thatCertificate);
}
}
}Create a Hibernate Mapping File
Let's create a mapping file that tells Hibernate how to map the defined classes to the database tables. The set> element will specify the SortedSet collection's rule.
<?xml version = "1.0" encoding = "utf-8"?>
<!DOCTYPE hibernate_mapping PUBLIC
"-//Hibernate/Hibernate-Mapping DTD//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.1.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 class="native"/>
</id>
<set name = "certificates" cascade="all" sort="MyClass">
<key column = "employee_id"/>
<one-to-many class="Certificate"/>
</set>
<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 certificate records.
</meta>
<id name = "id" type = "int" column = "id">
<generator class="native"/>
</id>
<property name = "name" column = "certificate-name" type = "string"/>
</class>
</hibernate_mapping>
Elements of the mapping file
-
The mapping document is an XML document with <hibernate-mapping> as root element that contains two <class>> elements, one for each class.
-
The <class> elements specify specific mappings between Java classes and database tables. The name attribute of the class element is used to specify the Java class name, and the table attribute is used to specify the database table name.
-
The <meta> element is optional and can be used to generate the class description.
-
The <id> element maps the class's unique ID attribute to the database table's primary key. The column attribute of the id element points to the column in the table, and the name attribute refers to the property in the class. The type attribute contains the hibernate sortedset mapping type, which converts Java data to SQL data types.
-
Within the id element, the <generator> element automatically generates the primary key values. The class attribute of this element is put to native, which instructs hibernate to use either the identity, sequence, or Hilo algorithms to generate the primary key, depending on the capabilities of the database.
-
Set the relationship between the Certificate and Employee classes using the <set> element. We told Hibernate to persist the Certificate objects alongside the Employee objects by using the cascade attribute in the set> element. The name attribute is set to the parent class's SortedSet variable, which in our case, certificates. The sort attribute is set to natural to enable natural sorting or to a custom class that implements java.util.Comparator. To reverse the sorting order implemented in the Certificate class, we used a class, MyClass, that implements java.util.Comparator.
-
The <property> element maps a database table column to a Java class property. The element's name attribute refers to the property in the class, while the column attribute refers to the column in the database table. The type attribute contains the hibernate sortedset mapping type, which converts Java data to SQL data types.
-
The <key> element is that column in the CERTIFICATE table that contains the foreign key to the parent object, EMPLOYEES.
-
The <one-to-many> element suggests that one Employee object is related to multiple Certificate objects, and thus the Certificate object always has an Employee parent. Depending on your needs, you can use <one-to-one>, <many-to-one> or <many-to-many> elements. If we switched this example to a many-to-many relationship, we'd need an association table to map the parent and child objects.
Suppose we use the sort="natural" setting. In that case, we do not need to create a separate class because the Certificate class already implements the Comparable interface. Hibernate will compare certificate names using the compareTo() method defined in the Certificate class. However, because we use a custom comparator class, MyClass, in our mapping file, we must create this class based on our sorting algorithm. Let us use this class to perform descending sorting in this class.
import java.util.Comparator;
public class MyClass implements Comparator<Certificate>{
public int compare(Certificate o1, Certificate o2) {
final int prev = -1;
final int next = 1;
/* To reverse the order, multiple by -1 */
if (o2 == null) {
return prev * -1;
}
Comparable thisCertificate = o1.getName();
Comparable thatCertificate = o2.getName();
if(thisCertificate == null) {
return next * 1;
} else if(thatCertificate == null) {
return prev * -1;
} else {
return thisCertificate.compareTo(thatCertificate) * -1;
}
}
}Make an Application Class
Finally, we'll create our application class, including the main() method for running the application. This application will be used to save a few Employees' records along with their certificates, and then we will perform CRUD operations.
import java.util.*;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
public class ManageEmployees {
private static SessionFactory fact;
public static void main(String[] args) {
try{
fact = new Configuration().configure().buildSessionFactory();
}
catch (Throwable e) {
System.err.println("Failed." + e);
throw new ExceptionInInitializerError(e);
}
ManageEmployee ManageE = new ManageEmployee();
/* Set of certificates for the first employee */
TreeSet set1 = new TreeSet();
set1.add(new Certificate("MCA"));
set1.add(new Certificate("MBA"));
set1.add(new Certificate("BBA"));
/* Add employee records in the database */
Integer empID1 = ME.add("Rakesh", "Patel", 8000, set1);
/* Set of certificates for the second employee */
TreeSet set2 = new TreeSet();
set2.add(new Certificate("BBA"));
set2.add(new Certificate("BA"));
/* Add another employee record in the database */
Integer empID2 = ME.add("Harish", "Kumar", 5000, set2);
/* List down all the employees */
ManageE.listEmployees();
/* Update employee's salary records */
ManageE.updateEmployee(empID1, 5000);
/* Delete an employee from the database */
ManageE.deleteEmployee(empID2);
/* List down all the employees */
ManageE.listEmployees();
}
/* Adding an employee record */
public Integer add(String f_name, String l_name, int salary, SortedSet cert){
Session s = factory.openSession();
Transaction t = null;
Integer employeeID = null;
try{
t = session.beginTransaction();
Employee employee = new Employee(f_name, l_name, salary);
employee.setCertificates(cert);
employeeID = (Integer) session.save(employee);
t.commit();
}
catch (HibernateException e) {
if (t!=null) t.rollback();
e.printStackTrace();
}
finally {
s.close();
}
return employeeID;
}
/* List all the employees detail */
public void listEmployees( ){
Session s = factory.openSession();
Transaction t = null;
try{
t = s.beginTransaction();
List employees = s.createQuery("FROM Employee").list();
for (Iterator itr1 = employees.iterator(); it1.hasNext();){
Employee employee = (Employee) it1.next();
System.out.print("First Name: " + employee.getFirstName());
System.out.print(" Last Name: " + employee.getLastName());
System.out.println(" Salary: " + employee.getSalary());
SortedSet certificates = employee.getCertificates();
for (Iterator it2 = certificates.iterator(); it2.hasNext();){
Certificate certName = (Certificate) it2.next();
System.out.println("Certificate: " + certName.getName());
}
}
t.commit();
}
catch (HibernateException e) {
if (t!=null) t.rollback();
e.printStackTrace();
}
finally {
s.close();
}
}
/* update salary for an employee */
public void updateEmployee(Integer EmployeeID, int salary ){
Session s = factory.openSession();
Transaction t = null;
try{
t = s.beginTransaction();
Employee employee = (Employee)s.get(Employee.class, EmployeeID);
employee.setSalary( salary );
s.update(employee);
t.commit();
}
catch (HibernateException e) {
if (t!=null) t.rollback();
e.printStackTrace();
}
finally {
s.close();
}
}
/* Delete an employee from the records */
public void deleteEmployee(Integer EmployeeID){
Session s = factory.openSession();
Transaction t = null;
try{
t = s.beginTransaction();
Employee employee = (Employee)s.get(Employee.class, EmployeeID);
s.delete(employee);
t.commit();
}
catch (HibernateException e) {
if (tx!=null) tx.rollback();
e.printStackTrace();
}
finally {
session.close();
}
}
}Compilation and Implementation
Before proceeding with the compilation and execution, ensure that PATH and CLASSPATH have been properly set.
- Create the hibernate.cfg.xml configuration file.
- As shown above, create the Employee.hbm.xml mapping file.
- Compile the Employee.java source file.
- Compile the Certificate.java source file.
- Compile the MyClass.java source file.
- Compile the ManageEmployee.java source file.
- To run the program, run the ManageEmployee binary.
The screen would display the following result, and records would be created simultaneously in the EMPLOYEE and CERTIFICATE tables.
As you can see, the certificates are sorted in reverse order. You can experiment by changing your mapping file, running your program, and comparing the results.
$java ManageEmployee
.......VARIOUS LOG MESSAGES WILL DISPLAY HERE........
First Name: Rakesh Last Name: Patel Salary: 8000
Certificate: MCA
Certificate: MBA
Certificate: BBA
First Name: Harish Last Name: Kumar Salary: 5000
Certificate: BBA
Certificate: BA
First Name: Rakesh Last Name: Patel Salary: 5000
Certificate: MCA
Certificate: MBA
Certificate: BBA
mysql> select * from employee;
+----+------------+-----------+--------+
| id | first_name | last_name | salary |
+----+------------+-----------+--------+
| 1 | Manoj | Kumar | 5000 |
+----+------------+-----------+--------+
1 row in set (0.00 sec)
mysql> select * from certificate;
+----+------------------+-------------+
| id | certificate_name | employee_id |
+----+------------------+-------------+
| 1 | MBA | 1 |
| 2 | MCA | 1 |
| 3 | BBA | 1 |
+----+------------------+-------------+
3 rows in set (0.00 sec)
mysql>





