Hibernate: tabla por jerarquía usando anotación

Hibernate es un marco que proporciona una capa de abstracción, lo que significa que el programador no tiene que preocuparse por las implementaciones, hace las implementaciones por usted internamente, como escribir consultas para realizar operaciones CRUD , establecer una conexión con la base de datos, etc. marco java ORM (mapeo relacional de objetos) de código abierto, no invasivo y livianoque se utiliza para desarrollar una lógica de persistencia que es independiente del software de la base de datos.

Hibernate es capaz de almacenar las propiedades heredadas de un objeto junto con sus nuevas propiedades en su base de datos cuando un objeto se guarda en la base de datos. En Hibernate, la herencia entre clases POJO se aplica cuando varias clases POJO de un módulo contienen algunas propiedades comunes. 

Mapeo de herencia de Hibernate

La orientación a objetos puede modelar las relaciones «es un» y «tiene un» . El modelo relacional solo admite la relación «tiene un» entre dos entidades. Hibernate ayuda a mapear dichos objetos con tablas relacionales. Hay tres estrategias de mapeo de herencia definidas en Hibernate.

  • Tabla por jerarquía
  • Tabla por clase de hormigón
  • Tabla por subclase

Tabla por jerarquía (usando anotaciones)

La tabla por jerarquía es una de las estrategias de herencia en hibernación. En esta estrategia, toda la jerarquía se asigna a una sola tabla. Todos los atributos de todas las clases en la jerarquía se almacenan en una sola tabla.

En una tabla por estrategia de jerarquía:

  • Solo se crea una tabla en la base de datos para almacenar datos de toda la jerarquía de clases.
  • Hibernate necesita una columna adicional en la tabla llamada columna discriminadora para colocar o almacenar el valor discriminador de un objeto de subclase.
  • La columna discriminadora es obligatoria mientras que es opcional en las otras dos estrategias de mapeo mencionadas anteriormente.

Un discriminador identifica de forma única el tipo base de la jerarquía de clases.

Anotaciones importantes

Anotación 1: @Herencia 

Esta anotación define la estrategia de herencia que se utilizará para una jerarquía de clase de entidad. Se especifica en la clase de entidad que es la raíz de la jerarquía de clases de entidad. Si no se especifica la anotación @Inheritance o si no se especifica herencia para una jerarquía de clase de entidad, se usa la estrategia de mapeo SINGLE_TABLE .

Sintaxis: @Herencia

@Entity
@Table("name = students")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
// Class 
public class Student {

    // Insert code here
}

Anotación 2: @DiscriminatorColumn

Esta anotación se usa para definir la columna discriminadora para las estrategias de mapeo de herencia SINGLE_TABLE y JOINED. La estrategia y la columna discriminadora solo se especifican en la raíz de una jerarquía o subjerarquía de clase de entidad en la que se aplica una estrategia de herencia diferente. Si no se especifica la anotación @DiscriminatorColumn y se requiere la columna discriminadora, en ese caso, el nombre de la columna discriminadora se establece en su valor predeterminado «DTYPE» y el tipo de discriminador se establece en DiscriminatorType.STRING .

@Entity
@Table("name = students")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "student", discriminatorType = DiscriminatorType.STRING)
// Class 
public class Student {

    // Insert code here
}

Anotaciones 3: @DiscriminatorValue 

Esta anotación se usa para establecer el valor de la columna discriminadora para entidades del tipo dado. Solo se puede especificar en una clase de entidad concreta. Si no se menciona la anotación @DiscriminatorValue y se usa una columna discriminadora, se usará una función específica del proveedor para generar un valor que represente el tipo de entidad. Si DiscriminatorType se especifica como STRING , el valor predeterminado del discriminador es el nombre de la propia entidad. La estrategia de herencia y la columna discriminadora solo se especifican en la raíz de una jerarquía o subjerarquía de clases de entidad en la que se aplica una estrategia de herencia diferente. Es la mejor práctica especificar el valor del discriminador para cada clase de entidad en la jerarquía.

@Entity
@Table("name = employees")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "employee", discriminatorType = DiscriminatorType.STRING)
// Class 
public class Employee{

    // Insert code here
}

@Entity
@DiscriminatorValue(value = "ceo")
// Class
public class Ceo extends Employee {

     // Insert code here
}

Implementación de tabla por jerarquía (usando anotaciones)

En este ejemplo, crearemos tres clases de persistencia con Employee como clase principal y P_Employee y C_Employee como las dos subclases.

Jerarquía de Clases

Jerarquía de Clases

Ahora, en este enfoque, toda la jerarquía se asigna a una sola tabla. Todos los atributos de todas las clases en la jerarquía se almacenan en una sola tabla.

Creación de una tabla de base de datos para conservar la jerarquía de clases

CREATE TABLE `Employee` (
 `id` BIGINT(20) NOT NULL AUTO_INCREMENT,
 `name` VARCHAR(50) NOT NULL DEFAULT '0',
 `age` BIGINT(3) NOT NULL DEFAULT '0',
 `salary` BIGINT(11) NULL DEFAULT NULL,
 `hourlyrate` BIGINT(11) NULL DEFAULT NULL,
 `duration` BIGINT(11) NULL DEFAULT NULL,
 `discriminator` VARCHAR(20) NOT NULL,
  PRIMARY KEY (`id`)
)

La tabla Employee almacenará objetos de las tres clases Employee, P_Employee y C_Employee .

Estructura del proyecto (IntelliJ IDEA):

Estructura del proyecto

Estructura del proyecto

Creación de las clases Employee, P_Employee y C_Employee para la jerarquía anterior:

A continuación se muestra la implementación del archivo Employee.java :

Java

package com.exploit.model;
 
import javax.persistence.Column;
import javax.persistence.DiscriminatorColumn;
import javax.persistence.DiscriminatorType;
import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.Table;
 
@Entity
@Table(name = "Employee")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "type",
                     discriminatorType
                     = DiscriminatorType.STRING)
@DiscriminatorValue(value = "EMP")
public class Employee {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "id")
    private int id;
    @Column(name = "name") private String name;
    @Column(name = "age") private int age;
 
    public int getAge() { return age; }
 
    public void setAge(int age) { this.age = age; }
 
    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; }
}

A continuación se muestra la implementación del archivo P_Employee.java :

Java

package com.exploit.model;
 
import javax.persistence.Column;
import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;
 
@Entity
@DiscriminatorValue(value = "PEMP")
public class P_Employee extends Employee {
 
    @Column(name = "salary") private double salary;
 
    public double getSalary() { return salary; }
 
    public void setSalary(double salary)
    {
        this.salary = salary;
    }
}

A continuación se muestra la implementación del archivo C_Employee.java :

Java

package com.exploit.model;
 
import javax.persistence.Column;
import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;
 
@Entity
@DiscriminatorValue(value = "CEMP")
public class C_Employee extends Employee {
 
    @Column(name = "hourlyRate") private double hourlyRate;
 
    @Column(name = "duration") private double duration;
 
    public double getDuration() { return duration; }
 
    public void setDuration(double duration)
    {
        this.duration = duration;
    }
 
    public double getHourlyRate() { return hourlyRate; }
 
    public void setHourlyRate(double hourlyRate)
    {
        this.hourlyRate = hourlyRate;
    }
}

Hemos definido los discriminadores como:  

  • “EMP” persistirá en la columna del discriminador perteneciente a la clase Empleado .
  • “PEMP” persistirá en la columna discriminadora perteneciente a la clase P_Employee .
  • “CEMP” persistirá en la columna del discriminador perteneciente a la clase C_Employee .

Crear un archivo de configuración hibernate.cgf.xml y agregar las entradas de los recursos de mapeo:

XML

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
 
<hibernate-configuration>
 
    <session-factory>
 
        <!-- Database connection properties -->
        <property name="connection.driver_class">com.mysql.jdbc.Driver</property>
        <property name="connection.url">jdbc:mysql://localhost/heistmvr</property>
        <property name="connection.username">root</property>
        <property name="connection.password">root</property>
 
        <!-- JDBC connection pool (using the built-in) -->
        <property name="connection.pool_size">100</property>
 
        <!-- SQL dialect -->
        <property name="dialect">org.hibernate.dialect.MySQLDialect</property>
 
        <!-- Disable the second-level cache -->
        <property name="cache.provider_class">org.hibernate.cache.internal.NoCacheProvider</property>
 
        <!-- Echo all executed SQL to stdout -->
        <property name="show_sql">true</property>
 
        <!-- Format the generated Sql -->
        <property name="format_sql">true</property>
 
        <!-- Dont Drop and re-create the database
             schema on startup,Just update it -->
        <property name="hbm2ddl.auto">update</property>
       
        <!-- Entries of mapping resources -->
        <mapping class="com.exploit.model.Employee"/>
        <mapping class="com.exploit.model.C_Employee"/>
        <mapping class="com.exploit.model.P_Employee"/>
 
    </session-factory>
 
</hibernate-configuration>

Las siguientes son las dependencias utilizadas en el archivo pom.xml:

XML

<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
                             http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
 
    <groupId>TablePerHierarchyAnnotation</groupId>
    <artifactId>TablePerHierarchyAnnotation</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>
 
    <name>TablePerHierarchyAnnotation</name>
    <url>http://maven.apache.org</url>
 
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
 
    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>3.8.1</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-core</artifactId>
            <version>5.2.6.Final</version>
        </dependency>
       
        <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>6.0.5</version>
        </dependency>
       
        <!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-annotations -->
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-annotations</artifactId>
            <version>3.5.6-Final</version>
        </dependency>
 
    </dependencies>
</project>

Creando la clase que almacena el objeto persistente:

A continuación se muestra la implementación del archivo Main.java

Java

package com.exploit.db;
 
import com.exploit.model.C_Employee;
import com.exploit.model.Employee;
import com.exploit.model.P_Employee;
import com.exploit.util.HibernateUtil;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
 
public class Main {
    public static void main(String[] args)
    {
        // Get session factory using Hibernate Util class
        SessionFactory sessionFactory
            = HibernateUtil.getSessionFactory();
       
        // Get session from Session factory
        Session session = sessionFactory.openSession();
 
        // Begin transaction
        Transaction transaction
            = session.beginTransaction();
 
        // Creating Employee base class record
        Employee employee = new Employee();
        employee.setName("KirikoChan");
        employee.setAge(19);
        // Creating Permanent Employee subclass record
        P_Employee permanentEmployee = new P_Employee();
        permanentEmployee.setName("Saili.H");
        permanentEmployee.setAge(20);
        permanentEmployee.setSalary(30000);
 
        // Creating Contract Employee subclass record
        C_Employee contractEmployee = new C_Employee();
        contractEmployee.setName("ChikkoRita");
        contractEmployee.setAge(21);
        contractEmployee.setHourlyRate(2000);
        contractEmployee.setDuration(7.5);
 
        // persist all the employee records
        session.persist(employee);
        session.persist(permanentEmployee);
        session.persist(contractEmployee);
 
        // Commit the transaction and close the session
        transaction.commit();
        session.close();
        System.out.println(
            "Employee records successfully persisted.");
    }
}

La clase principal se utiliza para conservar las instancias de objetos de las tres clases. Tenga en cuenta que ambas clases se conservan en la misma tabla Empleado. La columna discriminadora se utiliza para distinguir entre las entidades. Esta es la forma habitual de asignar tablas por jerarquía mediante anotaciones.

Publicación traducida automáticamente

Artículo escrito por kaalel y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *