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.
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):
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.