Hibernate - Asignaciones SortedSet

UN SortedSet es una colección de Java que no contiene ningún elemento duplicado y los elementos se ordenan utilizando su orden natural o mediante un comparador proporcionado.

Un SortedSet se asigna con un elemento <set> en la tabla de asignación y se inicializa con java.util.TreeSet. lossortEl atributo se puede establecer en un comparador o en un orden natural. Si usamosnatural ordenando, entonces su iterador atravesará el conjunto en orden ascendente de elementos.

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. Por lo tanto, 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_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 nuestra clase POJO Employee, que se utilizará para conservar los objetos relacionados con la tabla EMPLOYEE y tener una colección de certificados en 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 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 SortedSet getCertificates() {
      return certificates;
   }
   
   public void setCertificates( SortedSet certificates ) {
      this.certificates = certificates;
   }
}

Ahora definamos 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 debería implementarComparable interfaz y compareTo método, que se utilizará para ordenar los elementos 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 <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);
      }
   }
}

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 <set> se utilizará para definir la regla para la colección SortedSet utilizada.

<?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>
      <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 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 asignación 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 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 <set>El elemento se utiliza para establecer la relación entre las clases Certificado y Empleado. Usamos elcascadeatributo en el elemento <set> 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 SortedSetvariable 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 <key> El elemento es la columna de la tabla CERTIFICADO que contiene la clave externa del objeto principal, es decir, la 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 los nombres de los certificados. 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 en esta clase usando esta clase.

import java.util.Comparator;

public class MyClass implements Comparator<Certificate>{
   public int compare(Certificate o1, Certificate 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.getName();
      Comparable thatCertificate = o2.getName();

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

Crear clase de aplicación

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 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  */
      TreeSet set1 = new TreeSet();
      set1.add(new Certificate("MCA"));
      set1.add(new Certificate("MBA"));
      set1.add(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  */
      TreeSet set2 = new TreeSet();
      set2.add(new Certificate("BCA"));
      set2.add(new Certificate("BA"));

      /* 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, SortedSet 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());
            SortedSet certificates = employee.getCertificates();
            for (Iterator iterator2 = certificates.iterator(); iterator2.hasNext();){
               Certificate certName = (Certificate) iterator2.next(); 
               System.out.println("Certificate: " + certName.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 los certificados se han clasificado 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: PMP
Certificate: MCA
Certificate: MBA
First Name: Dilip  Last Name: Kumar  Salary: 3000
Certificate: BCA
Certificate: BA
First Name: Manoj  Last Name: Kumar  Salary: 5000
Certificate: PMP
Certificate: MCA
Certificate: MBA

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

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  | PMP              |          1  |
| 3  | MCA              |          1  |
+----+------------------+-------------+
3 rows in set (0.00 sec)

mysql>