Hibernate: asignación de herencia

La jerarquía de herencia se puede ver fácilmente en la tabla de la base de datos. En Hibernate tenemos tres estrategias diferentes disponibles para el mapeo de herencia

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

La jerarquía se puede ver esquemáticamente fácilmente.

 

En este artículo, veamos acerca de la tabla por jerarquía usando XML. También se puede hacer usando anotaciones. Aquí toda la jerarquía está siendo mapeada por una sola tabla. Se crea una columna discriminadora (diferenciadora) en la tabla para identificar la clase. Tomemos una muestra entre el trabajador regular y el trabajador por contrato que se asignan desde el trabajador

Proyecto de ejemplo

Estructura de la tabla MySQL

create table worker(
    workerId int auto_increment,
    workerName varchar(25),
    salary float,
    additionalBenefits int,
    pricePerHour float,
    contractPeriod varchar(25),
Primary key (workerId)
);

La tabla MySQL llamada ‘trabajador’ se crea con las columnas necesarias. Al ver los nombres de las columnas, podemos llegar a saber que workerId y workerName deberían estar disponibles en la clase Main Worker. salario y beneficios adicionales serían para RegularWorker. pricePerHour y contractPeriod serían para ContractWorker.

Estructura del proyecto:

Project Structure

 

Como este es el proyecto maven, agreguemos 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
                             https://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>Inheritence</groupId>
  <artifactId>Inheritence</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <build>
    <sourceDirectory>src</sourceDirectory>
    <resources>
      <resource>
        <directory>src</directory>
        <excludes>
          <exclude>**/*.java</exclude>
        </excludes>
      </resource>
    </resources>
    <plugins>
      <plugin>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.8.1</version>
        <configuration>
          <release>9</release>
        </configuration>
      </plugin>
    </plugins>
  </build>
  <dependencies>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-core</artifactId>
            <version>5.4.15.Final</version>
        </dependency>
        <!-- As we are connecting with MySQL, this is needed -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.34</version>
        </dependency>
    </dependencies>
    <properties>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>
</project>

Como todas las columnas se especifican en una sola tabla, deben distinguirse mediante una columna discriminadora. Se especifica en el archivo hbm. Veamos worker.hbm.xml

trabajador.hbm.xml

XML

<?xml version='1.0' encoding='UTF-8'?> 
<!DOCTYPE hibernate-mapping PUBLIC 
          "-//Hibernate/Hibernate Mapping DTD 5.3//EN" 
          "http://hibernate.sourceforge.net/hibernate-mapping-5.3.dtd"> 
   
<hibernate-mapping> 
    
      <!-- Referring to Worker bean -->
    <class name="com.gfg.hierarchy.Worker" table="worker" discriminator-value="worker"> 
      <id name="workerId"> 
          <generator class="increment"></generator> 
      </id> 
 
      <!-- As all columns are kept in the same table, we need to have
           a separate column named "type". It should inform about the
           type of worker. Here it can be Worker/RegularWorker/ContractWorker -->
      <discriminator column="type" type="string"></discriminator> 
      <property name="workerName"></property> 
 
       <!-- RegularWorker is inherited from Worker and hence it should be denoted with subclass
            and its discriminator-value="regularworker" -->
      <subclass name="com.gfg.hierarchy.RegularWorker" discriminator-value="regularworker"> 
        <property name="salary"></property> 
        <property name="additionalBenefits"></property> 
      </subclass>
 
       <!-- ContractWorker is inherited from Worker and hence
            it should be denoted with subclass
            and its discriminator-value="contractworker" -->
      <subclass name="com.gfg.hierarchy.ContractWorker" discriminator-value="contractworker"> 
        <property name="pricePerHour"></property> 
        <property name="contractPeriod"></property> 
      </subclass> 
 
    </class> 
             
</hibernate-mapping>

Estamos usando MYSQL y, por lo tanto, esas configuraciones deben especificarse en hibernate.cfg.xml

hibernate.cfg.xml

XML

<?xml version='1.0' encoding='UTF-8'?> 
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <session-factory>
        <!--  As we are connecting mysql, those driver classes,
              database name, username and password are specified
              Please change the information as per your requirement -->
        <property name="hbm2ddl.auto">update</property> 
        <property name="connection.driver_class">com.mysql.jdbc.Driver</property>
        <property name="connection.url">jdbc:mysql://localhost:3306/geeksforgeeks?serverTimezone=UTC</property>       
        <property name="connection.username">root</property>
        <property name="connection.password">admin</property>
         
          <!--  We are going to connect worker.hbm.xml which has
              the table information about worker which is present in mysql -->
        <mapping resource="worker.hbm.xml" />
    </session-factory>
</hibernate-configuration>

Veamos las clases de bean equivalentes.

Trabajador.java

Java

public class Worker {
    // Only the columns required for Worker is specified
    // As RegularWorker and ContractWorker are extended
    // from this, those required columns
    // are specified in those tables
    private int workerId;
    private String workerName;
 
    public int getWorkerId() {
        return workerId;
    }
 
    public void setWorkerId(int workerId) {
        this.workerId = workerId;
    }
 
    public String getWorkerName() {
        return workerName;
    }
 
    public void setWorkerName(String workerName) {
        this.workerName = workerName;
    }
}

RegularWorker.java

Java

public class RegularWorker extends Worker {
    // We are specifying only the columns
    // required for RegularWorker
    // Hence salary and additionalBenefits
    // are specified here
    private float salary;
    private int additionalBenefits;
 
    public float getSalary() {
        return salary;
    }
 
    public void setSalary(float salary) {
        this.salary = salary;
    }
 
    public int getAdditionalBenefits() {
        return additionalBenefits;
    }
 
    public void setAdditionalBenefits(int additionalBenefits) {
        this.additionalBenefits = additionalBenefits;
    }
 
}

ContractWorker.java

Java

public class ContractWorker extends Worker{
    // only the columns required for
    // ContractWorker are specified here
    private float pricePerHour; 
    private String contractPeriod;
    public float getPricePerHour() {
        return pricePerHour;
    }
    public void setpricePerHour(float pricePerHour) {
        this.pricePerHour = pricePerHour;
    }
    public String getContractPeriod() {
        return contractPeriod;
    }
    public void setContractPeriod(String contractPeriod) {
        this.contractPeriod = contractPeriod;
    }  
} 

El archivo worker.hbm.xml es el archivo clave muy importante y para la «Tabla por jerarquía», la columna discriminadora es el elemento esencial.

TablePerHierarchyWayOfStoringData.java

Java

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.boot.Metadata;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder; 
public class TablePerHierarchyWayOfStoringData { 
public static void main(String[] args) { 
     
    StandardServiceRegistry standardServiceRegistry = new StandardServiceRegistryBuilder().configure("hibernate.cfg.xml").build();
    Metadata metaData=new MetadataSources(standardServiceRegistry).getMetadataBuilder().build();
     
    SessionFactory factory=metaData.getSessionFactoryBuilder().build();
    Session session=factory.openSession();
   
    Transaction transaction=session.beginTransaction(); 
      
    // This will indicate for  the Worker class
    Worker worker=new Worker(); 
    worker.setWorkerName("Rachel Green"); 
       
    // This will indicate for  the RegularWorker class
    RegularWorker regularWorker=new RegularWorker(); 
    regularWorker.setWorkerName("Ross"); 
    regularWorker.setSalary(100000); 
    regularWorker.setAdditionalBenefits(50); 
       
    // This will indicate for  the ContractWorker class
    ContractWorker contractWorker=new ContractWorker(); 
    contractWorker.setWorkerName("Joey Tribbiani"); 
    contractWorker.setpricePerHour(5000); 
    contractWorker.setContractPeriod("25 hours"); 
       
    session.persist(worker); 
    session.persist(regularWorker); 
    session.persist(contractWorker); 
       
    transaction.commit(); 
    session.close(); 
    System.out.println("success. We can see 3 records got inserted in worker table and type is the discriminator column"); 
} 
}

Ejecución del programa y su salida.

 

Podemos verificar lo mismo consultando los datos de la base de datos de la tabla de trabajadores. Al ejecutar el código anterior, se insertan 3 registros diferentes. El flujo sigue como la tabla por jerarquía y, por lo tanto, todos los datos se insertarán en una sola tabla. En este ejemplo, use «trabajador» como nombre de tabla y «tipo» como columna discriminadora, y debajo está la salida.

 

Además, la herencia se puede ver a través de la clase Table Per Concrete (las tablas se crean según la clase) y Table Per Subclass (las tablas se crean según la clase pero están relacionadas por la clave externa).

Publicación traducida automáticamente

Artículo escrito por priyarajtt 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 *