Hibernate - Asignaciones SortedMap

UN SortedMap es una colección java similar a Mapque almacena elementos en pares clave-valor y proporciona un orden total en sus claves. No se permiten elementos duplicados en el mapa. El mapa se ordena de acuerdo con el orden natural de sus claves, o mediante un comparador que normalmente se proporciona en el momento de la creación del mapa ordenado.

Un SortedMap se asigna con un elemento <map> en la tabla de asignación y un mapa ordenado se puede inicializar con java.util.TreeMap.

Definir tablas RDBMS

Considere una situación en la que necesitamos almacenar nuestros registros de empleados en la tabla EMPLOYEE que tendrá la siguiente estructura:

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)
);

Además, suponga que cada empleado puede tener uno o más certificados asociados a él. Almacenaremos la información relacionada con el certificado en una tabla separada que tiene la siguiente estructura:

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)
);

Habrá one-to-many relación entre los objetos EMPLEADO y CERTIFICADO.

Definir clases POJO

Implementemos una clase POJO Employee, que se utilizará para conservar los objetos relacionados con la tabla EMPLOYEE y tener una colección de certificados en List variable.

import java.util.*;

public class Employee {
   private int id;
   private String firstName; 
   private String lastName;   
   private int salary;
   private SortedMap 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 SortedMap getCertificates() {
      return certificates;
   }
   
   public void setCertificates( SortedMap certificates ) {
      this.certificates = certificates;
   }
}

Necesitamos definir otra clase POJO correspondiente a la tabla CERTIFICATE para que los objetos de certificado se puedan almacenar y recuperar en la tabla CERTIFICATE. Esta clase también debe implementar la interfaz Comparable y el método compareTo que se utilizará para ordenar los elementos clave del SortedMap en caso de que establezca sort = "natural" en su archivo de mapeo (vea el archivo de mapeo a continuación).

public class Certificate implements Comparable <String>{
   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(String that){
      final int BEFORE = -1;
      final int AFTER = 1;

      if (that == null) {
         return BEFORE;
      }

      Comparable thisCertificate = this;
      Comparable thatCertificate = that;

      if(thisCertificate == null) {
         return AFTER;
      } else if(thatCertificate == null) {
         return BEFORE;
      } else {
         return thisCertificate.compareTo(thatCertificate);
      }
   }
}

Definir archivo de asignación de Hibernate

Desarrollemos nuestro archivo de mapeo que le indica a Hibernate cómo mapear las clases definidas a las tablas de la base de datos. El elemento <map> se utilizará para definir la regla para el mapa utilizado.

<?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 class="native"/>
      </id>
      
      <map name = "certificates" cascade="all" sort="MyClass">
         <key column = "employee_id"/>
         <index column = "certificate_type" type = "string"/>
         <one-to-many class="Certificate"/>
      </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 class="native"/>
      </id>
      
      <property name = "name" column = "certificate_name" type = "string"/>
      
   </class>

</hibernate-mapping>

Debe guardar el documento de mapeo en un archivo con el formato <classname> .hbm.xml. Guardamos nuestro documento de mapeo en el archivo Employee.hbm.xml. Ya está familiarizado con la mayoría de los detalles del mapeo, pero veamos todos los elementos del archivo de mapeo una vez más:

  • El documento de mapeo es un documento XML que tiene <hibernate-mapping> como el elemento raíz que contiene dos elementos <class> correspondientes a cada clase.

  • los <class>Los elementos se utilizan para definir asignaciones específicas de clases Java a las tablas de la base de datos. El nombre de la clase Java se especifica mediante elname El atributo del elemento de clase y el nombre de la tabla de la base de datos se especifica utilizando el table atributo.

  • los <meta> El elemento es un elemento opcional y se puede utilizar para crear la descripción de la clase.

  • los <id>El elemento asigna el atributo de ID único en la clase a la clave principal de la tabla de la base de datos. losname atributo del elemento id se refiere a la propiedad en la clase y el columnEl atributo se refiere a la columna de la tabla de la base de datos. lostype El atributo contiene el tipo de mapeo de hibernación, estos tipos de mapeo se convertirán del tipo de datos Java a SQL.

  • los <generator>El elemento dentro del elemento id se utiliza para generar los valores de clave primaria automáticamente. losclass atributo del elemento generador se establece en native para dejar que hibernate retome identity, sequence o hilo algoritmo para crear la clave principal en función de las capacidades de la base de datos subyacente.

  • los <property>El elemento se utiliza para asignar una propiedad de clase Java a una columna en la tabla de la base de datos. losname atributo del elemento se refiere a la propiedad en la clase y el columnEl atributo se refiere a la columna de la tabla de la base de datos. lostype El atributo contiene el tipo de mapeo de hibernación, estos tipos de mapeo se convertirán del tipo de datos Java a SQL.

  • los <map>El elemento se utiliza para establecer la relación entre las clases Certificado y Empleado. Usamos elcascadeatributo en el elemento <map> para decirle a Hibernate que persista los objetos de Certificado al mismo tiempo que los objetos de Empleado. losname el atributo se establece en el definido SortedMapvariable en la clase padre, en nuestro caso son certificados . lossort El atributo se puede establecer en natural para tener una ordenación natural o se puede configurar en una clase personalizada que implemente java.util.Comparator. Hemos usado una claseMyClass que implementa java.util.Comparator para invertir el orden de clasificación implementado en Certificate clase.

  • los <index>El elemento se utiliza para representar las partes clave del par de mapas clave / valor. La clave se almacenará en la columna certificate_type utilizando un tipo de cadena.

  • los <key>El elemento es la columna de la tabla CERTIFICADO que contiene la clave externa del objeto principal, es decir. tabla EMPLEADO.

  • los <one-to-many>El elemento indica que un objeto Empleado se relaciona con muchos objetos Certificado y, como tal, el objeto Certificado debe tener un padre Empleado asociado. Puedes usar cualquiera<one-to-one>, <many-to-one> o <many-to-many> elementos basados ​​en su requerimiento.

Si usamos sort="natural"entonces no necesitamos crear una clase separada porque la clase Certificate ya ha implementado la interfaz Comparable e hibernate usará el método compareTo () definido en la clase Certificate para comparar las claves de SortedMap. Pero estamos usando una clase comparadora personalizadaMyClassen nuestro archivo de mapeo, por lo que tendríamos que crear esta clase en función de nuestro algoritmo de clasificación. Hagamos una clasificación descendente de las claves disponibles en el mapa.

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;
      }
   }
}

Finalmente, crearemos nuestra clase de aplicación con el método main () para ejecutar la aplicación. Usaremos esta aplicación para guardar algunos registros de los empleados junto con sus certificados y luego aplicaremos operaciones CRUD en esos registros.

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.listEmployees();

      /* 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 detail */
   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)session.get(Employee.class, EmployeeID); 
         session.delete(employee); 
         tx.commit();
      } catch (HibernateException e) {
         if (tx!=null) tx.rollback();
         e.printStackTrace(); 
      } finally {
         session.close(); 
      }
   }
}

Compilación y ejecución

Estos son los pasos para compilar y ejecutar la aplicación mencionada anteriormente. Asegúrese de haber configurado PATH y CLASSPATH correctamente antes de continuar con la compilación y ejecución.

  • Cree el archivo de configuración hibernate.cfg.xml como se explica en el capítulo de configuración.

  • Cree el archivo de mapeo Employee.hbm.xml como se muestra arriba.

  • Cree el archivo fuente Employee.java como se muestra arriba y compílelo.

  • Cree el archivo fuente Certificate.java como se muestra arriba y compílelo.

  • Cree el archivo fuente MyClass.java como se muestra arriba y compílelo.

  • Cree el archivo fuente ManageEmployee.java como se muestra arriba y compílelo.

  • Ejecute el binario ManageEmployee para ejecutar el programa.

Obtendría el siguiente resultado en la pantalla, y al mismo tiempo se crearían registros en las tablas EMPLOYEE y CERTIFICATE. Puede ver que el tipo de certificado se ha ordenado en orden inverso. Puede probar cambiando su archivo de mapeo, simplemente configuresort="natural" y ejecute su programa y compare los resultados.

$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: MBA
First Name: Dilip  Last Name: Kumar  Salary: 3000
	Certificate Type: ComputerScience,  Name: MCA
	Certificate Type: BusinessManagement,  Name: MBA
First Name: Manoj  Last Name: Kumar  Salary: 5000
	Certificate Type: ProjectManagement,  Name: PMP
	Certificate Type: ComputerScience,  Name: MCA
	Certificate Type: BusinessManagement,  Name: MBA

Si revisa sus tablas EMPLEADO y CERTIFICADO, deben tener los siguientes registros:

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;
+----+--------------------+------------------+-------------+
| id | certificate_type   | certificate_name | employee_id |
+----+--------------------+------------------+-------------+
| 52 | BusinessManagement | MBA              |          74 |
| 53 | ComputerScience    | MCA              |          74 |
| 54 | ProjectManagement  | PMP              |          74 |
+----+--------------------+------------------+-------------+
3 rows in set (0.00 sec)

mysql>