JPA - Mapeamentos Avançados

JPA é uma biblioteca lançada com especificações java. Portanto, ele suporta todos os conceitos orientados a objetos para persistência de entidade. Até agora, concluímos os fundamentos do mapeamento relacional de objetos. Este capítulo o conduz pelos mapeamentos avançados entre objetos e entidades relacionais.

Estratégias de herança

Herança é o conceito central da linguagem orientada a objetos, portanto, podemos usar relacionamentos ou estratégias de herança entre entidades. JPA oferece suporte a três tipos de estratégias de herança, como SINGLE_TABLE, JOINED_TABLE e TABLE_PER_CONCRETE_CLASS.

Vamos considerar um exemplo de classes Staff, TeachingStaff, NonTeachingStaff e seus relacionamentos da seguinte forma:

No diagrama mostrado acima, Staff é uma entidade e TeachingStaff e NonTeachingStaff são as subentidades de Staff. Aqui, discutiremos o exemplo acima em todas as três estratégias de herança.

Estratégia de mesa única

A estratégia de tabela única pega todos os campos de classes (super e subclasses) e os mapeia em uma única tabela conhecida como estratégia SINGLE_TABLE. Aqui, o valor discriminador desempenha um papel fundamental na diferenciação dos valores de três entidades em uma tabela.

Vamos considerar o exemplo acima, TeachingStaff e NonTeachingStaff são as subclasses da classe Staff. Lembre o conceito de herança (é um mecanismo de herdar as propriedades de superclasse por subclasse) e, portanto, sid, sname são os campos que pertencem a TeachingStaff e NonTeachingStaff. Crie um projeto JPA. Todos os módulos deste projeto da seguinte forma:

Criando Entidades

Crie um pacote chamado ‘com.tutorialspoint.eclipselink.entity’ debaixo ‘src’pacote. Crie uma nova classe java chamadaStaff.javasob determinado pacote. A classe de entidade Staff é mostrada da seguinte forma:

package com.tutorialspoint.eclipselink.entity;

import java.io.Serializable;

import javax.persistence.DiscriminatorColumn;
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
@Inheritance( strategy = InheritanceType.SINGLE_TABLE )
@DiscriminatorColumn( name = "type" )

public class Staff implements Serializable {
   @Id
   @GeneratedValue( strategy = GenerationType.AUTO )
   
   private int sid;
   private String sname;
   
   public Staff( int sid, String sname ) {
      super( );
      this.sid = sid;
      this.sname = sname;
   }
   
   public Staff( ) {
      super( );
   }
   
   public int getSid( ) {
      return sid;
   }
   
   public void setSid( int sid ) {
      this.sid = sid;
   }
   
   public String getSname( ) {
      return sname;
   }
   
   public void setSname( String sname ) {
      this.sname = sname;
   }
}

No código acima @DescriminatorColumn especifica o nome do campo (type) e os valores mostram os campos restantes (Teaching e NonTeachingStaff).

Crie uma subclasse (classe) para a classe Staff chamada TeachingStaff.java debaixo de com.tutorialspoint.eclipselink.entitypacote. A classe TeachingStaff Entity é mostrada da seguinte forma:

package com.tutorialspoint.eclipselink.entity;

import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;

@Entity
@DiscriminatorValue( value="TS" )
public class TeachingStaff extends Staff {

   private String qualification;
   private String subjectexpertise;

   public TeachingStaff( int sid, String sname, 
   
   String qualification,String subjectexpertise ) {
      super( sid, sname );
      this.qualification = qualification;
      this.subjectexpertise = subjectexpertise;
   }

   public TeachingStaff( ) {
      super( );
   }

   public String getQualification( ){
      return qualification;
   }

   public void setQualification( String qualification ){
      this.qualification = qualification;
   }

   public String getSubjectexpertise( ) {
      return subjectexpertise;
   }

   public void setSubjectexpertise( String subjectexpertise ){
      this.subjectexpertise = subjectexpertise;
   }
}

Crie uma subclasse (classe) para a classe Staff chamada NonTeachingStaff.java debaixo de com.tutorialspoint.eclipselink.entitypacote. A classe NonTeachingStaff Entity é mostrada da seguinte forma:

package com.tutorialspoint.eclipselink.entity;

import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;

@Entity
@DiscriminatorValue( value = "NS" )

public class NonTeachingStaff extends Staff {
   private String areaexpertise;

   public NonTeachingStaff( int sid, String sname, String areaexpertise ) {
      super( sid, sname );
      this.areaexpertise = areaexpertise;
   }

   public NonTeachingStaff( ) {
      super( );
   }

   public String getAreaexpertise( ) {
      return areaexpertise;
   }

   public void setAreaexpertise( String areaexpertise ){
      this.areaexpertise = areaexpertise;
   }
}

Persistence.xml

O arquivo Persistence.xml contém as informações de configuração do banco de dados e as informações de registro das classes de entidade. O arquivo xml é mostrado da seguinte forma:

<?xml version="1.0" encoding="UTF-8"?>

<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
   xsi:schemaLocation="http://java.sun.com/xml/ns/persistence 
   http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">

   <persistence-unit name="Eclipselink_JPA" transaction-type="RESOURCE_LOCAL">
   
      <class>com.tutorialspoint.eclipselink.entity.Staff</class>
      <class>com.tutorialspoint.eclipselink.entity.NonTeachingStaff</class>
      <class>com.tutorialspoint.eclipselink.entity.TeachingStaff</class>
      
      <properties>
         <property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/jpadb"/>
         <property name="javax.persistence.jdbc.user" value="root"/>
         <property name="javax.persistence.jdbc.password" value="root"/>
         <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
         <property name="eclipselink.logging.level" value="FINE"/>
         <property name="eclipselink.ddl-generation" value="create-tables"/>
      </properties>
      
   </persistence-unit>
</persistence>

Classe de serviço

As classes de serviço são a parte de implementação do componente de negócios. Crie um pacote em‘src’ pacote chamado ‘com.tutorialspoint.eclipselink.service’.

Crie uma classe chamada SaveClient.java no pacote fornecido para armazenar os campos de classe Staff, TeachingStaff e NonTeachingStaff. A classe SaveClient é mostrada da seguinte forma:

package com.tutorialspoint.eclipselink.service;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import com.tutorialspoint.eclipselink.entity.NonTeachingStaff;
import com.tutorialspoint.eclipselink.entity.TeachingStaff;

public class SaveClient {

   public static void main( String[ ] args ) {
   
      EntityManagerFactory emfactory = Persistence.createEntityManagerFactory( "Eclipselink_JPA" );
      EntityManager entitymanager = emfactory.createEntityManager( );
      entitymanager.getTransaction( ).begin( );

      //Teaching staff entity 
      TeachingStaff ts1=new TeachingStaff(1,"Gopal","MSc MEd","Maths");
      TeachingStaff ts2=new TeachingStaff(2, "Manisha", "BSc BEd", "English");
      
      //Non-Teaching Staff entity
      NonTeachingStaff nts1=new NonTeachingStaff(3, "Satish", "Accounts");
      NonTeachingStaff nts2=new NonTeachingStaff(4, "Krishna", "Office Admin");

      //storing all entities
      entitymanager.persist(ts1);
      entitymanager.persist(ts2);
      entitymanager.persist(nts1);
      entitymanager.persist(nts2);
      
      entitymanager.getTransaction().commit();
      
      entitymanager.close();
      emfactory.close();
   }
}

Após a compilação e execução do programa acima, você receberá notificações no painel do console do Eclipse IDE. Verifique o ambiente de trabalho MySQL para saída. A saída em formato tabular é mostrada da seguinte forma:

Sid Tipo Sname Experiência da área Qualificação Experiência do assunto
1 TS Gopal MSC MED Matemáticas
2 TS Manisha BSC BED Inglês
3 NS Satish Contas
4 NS Krishna Admin de escritório

Finalmente você terá uma única tabela que contém todos os três campos da classe e difere com a coluna discriminadora chamada ‘Type’ (campo).

Estratégia de mesa junta

A estratégia da tabela associada é compartilhar a coluna referenciada que contém valores únicos para juntar a tabela e fazer transações fáceis. Vamos considerar o mesmo exemplo acima.

Crie um projeto JPA. Todos os módulos do projeto são mostrados a seguir:

Criando Entidades

Crie um pacote chamado ‘com.tutorialspoint.eclipselink.entity’ debaixo ‘src’pacote. Crie uma nova classe java chamadaStaff.javasob determinado pacote. A classe de entidade Staff é mostrada da seguinte forma:

package com.tutorialspoint.eclipselink.entity;

import java.io.Serializable;

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
@Inheritance( strategy = InheritanceType.JOINED )

public class Staff implements Serializable {

   @Id
   @GeneratedValue( strategy = GenerationType.AUTO )
   
   private int sid;
   private String sname;
   
   public Staff( int sid, String sname ) {
      super( );
      this.sid = sid;
      this.sname = sname;
   }
   
   public Staff( ) {
      super( );
   }
   
   public int getSid( ) {
      return sid;
   }
   
   public void setSid( int sid ) {
      this.sid = sid;
   }
   
   public String getSname( ) {
      return sname;
   }
   
   public void setSname( String sname ) {
      this.sname = sname;
   }
}

Crie uma subclasse (classe) para a classe Staff chamada TeachingStaff.java debaixo de com.tutorialspoint.eclipselink.entitypacote. A classe TeachingStaff Entity é mostrada da seguinte forma:

package com.tutorialspoint.eclipselink.entity;

import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;

@Entity
@PrimaryKeyJoinColumn(referencedColumnName="sid")

public class TeachingStaff extends Staff {
   private String qualification;
   private String subjectexpertise;

   public TeachingStaff( int sid, String sname, 
   
   String qualification,String subjectexpertise ) {
      super( sid, sname );
      this.qualification = qualification;
      this.subjectexpertise = subjectexpertise;
   }

   public TeachingStaff( ) {
      super( );
   }

   public String getQualification( ){
      return qualification;
   }

   public void setQualification( String qualification ){
      this.qualification = qualification;
   }

   public String getSubjectexpertise( ) {
      return subjectexpertise;
   }

   public void setSubjectexpertise( String subjectexpertise ){
      this.subjectexpertise = subjectexpertise;
   }
}

Crie uma subclasse (classe) para a classe Staff chamada NonTeachingStaff.java debaixo de com.tutorialspoint.eclipselink.entitypacote. A classe NonTeachingStaff Entity é mostrada da seguinte forma:

package com.tutorialspoint.eclipselink.entity;

import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;

@Entity
@PrimaryKeyJoinColumn(referencedColumnName="sid")

public class NonTeachingStaff extends Staff {
   private String areaexpertise;

   public NonTeachingStaff( int sid, String sname, String areaexpertise ) {
      super( sid, sname );
      this.areaexpertise = areaexpertise;
   }

   public NonTeachingStaff( ) {
      super( );
   }

   public String getAreaexpertise( ) {
      return areaexpertise;
   }

   public void setAreaexpertise( String areaexpertise ) {
      this.areaexpertise = areaexpertise;
   }
}

Persistence.xml

O arquivo Persistence.xml contém as informações de configuração do banco de dados e as informações de registro das classes de entidade. O arquivo xml é mostrado da seguinte forma:

<?xml version = "1.0" encoding = "UTF-8"?>

<persistence version = "2.0" xmlns = "http://java.sun.com/xml/ns/persistence" 
   xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance" 
   xsi:schemaLocation = "http://java.sun.com/xml/ns/persistence 
   http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
   
   <persistence-unit name = "Eclipselink_JPA" transaction-type = "RESOURCE_LOCAL">
      <class>com.tutorialspoint.eclipselink.entity.Staff</class>
      <class>com.tutorialspoint.eclipselink.entity.NonTeachingStaff</class>
      <class>com.tutorialspoint.eclipselink.entity.TeachingStaff</class>
      
      <properties>
         <property name = "javax.persistence.jdbc.url" value = "jdbc:mysql://localhost:3306/jpadb"/>
         <property name = "javax.persistence.jdbc.user" value = "root"/>
         <property name = "javax.persistence.jdbc.password" value = "root"/>
         <property name = "javax.persistence.jdbc.driver" value = "com.mysql.jdbc.Driver"/>
         <property name = "eclipselink.logging.level" value = "FINE"/>
         <property name = "eclipselink.ddl-generation" value = "create-tables"/>
      </properties>
      
   </persistence-unit>
</persistence>

Classe de serviço

As classes de serviço são a parte de implementação do componente de negócios. Crie um pacote em‘src’ pacote chamado ‘com.tutorialspoint.eclipselink.service’.

Crie uma classe chamada SaveClient.java no pacote fornecido para armazenar os campos de classe Staff, TeachingStaff e NonTeachingStaff. Em seguida, a classe SaveClient da seguinte maneira:

package com.tutorialspoint.eclipselink.service;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import com.tutorialspoint.eclipselink.entity.NonTeachingStaff;
import com.tutorialspoint.eclipselink.entity.TeachingStaff;

public class SaveClient {
   public static void main( String[ ] args ) {
      EntityManagerFactory emfactory = Persistence.createEntityManagerFactory( "Eclipselink_JPA" );
      EntityManager entitymanager = emfactory.createEntityManager( );
      entitymanager.getTransaction( ).begin( );

      //Teaching staff entity 
      TeachingStaff ts1 = new TeachingStaff(1,"Gopal","MSc MEd","Maths");
      TeachingStaff ts2 = new TeachingStaff(2, "Manisha", "BSc BEd", "English");
      
      //Non-Teaching Staff entity
      NonTeachingStaff nts1 = new NonTeachingStaff(3, "Satish", "Accounts");
      NonTeachingStaff nts2 = new NonTeachingStaff(4, "Krishna", "Office Admin");

      //storing all entities
      entitymanager.persist(ts1);
      entitymanager.persist(ts2);
      entitymanager.persist(nts1);
      entitymanager.persist(nts2);

      entitymanager.getTransaction().commit();
      entitymanager.close();
      emfactory.close();
   }
}

Após a compilação e execução do programa acima, você receberá notificações no painel do console do Eclipse IDE. Para a saída, verifique o ambiente de trabalho MySQL da seguinte maneira:

Aqui três tabelas são criadas e o resultado de staff tabela em formato tabular é mostrada da seguinte forma:

Sid Dtype Sname
1 Pessoal docente Gopal
2 Pessoal docente Manisha
3 NonTeachingStaff Satish
4 NonTeachingStaff Krishna

O resultado de TeachingStaff tabela em formato tabular é mostrada da seguinte forma:

Sid Qualificação Experiência do assunto
1 MSC MED Matemáticas
2 BSC BED Inglês

Na tabela acima, sid é a chave estrangeira (campo de referência da tabela de funcionários). O resultado de NonTeachingStaff tabela em formato tabular é mostrada da seguinte forma:

Sid Experiência da área
3 Contas
4 Admin de escritório

Finalmente, as três tabelas são criadas usando seus campos respectivamente e o campo SID é compartilhado por todas as três tabelas. Na tabela de equipe, o SID é a chave primária, nas demais tabelas (TeachingStaff e NonTeachingStaff), o SID é a chave estrangeira.

Tabela por estratégia de classe

A estratégia de tabela por classe consiste em criar uma tabela para cada subentidade. A mesa da equipe será criada, mas conterá registros nulos. Os valores dos campos da tabela Staff devem ser compartilhados pelas tabelas TeachingStaff e NonTeachingStaff.

Vamos considerar o mesmo exemplo acima. Todos os módulos deste projeto são mostrados a seguir:

Criando Entidades

Crie um pacote chamado ‘com.tutorialspoint.eclipselink.entity’ debaixo ‘src’pacote. Crie uma nova classe java chamadaStaff.javasob determinado pacote. A classe de entidade Staff é mostrada da seguinte forma:

package com.tutorialspoint.eclipselink.entity;

import java.io.Serializable;

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
@Inheritance( strategy = InheritanceType.TABLE_PER_CLASS )

public class Staff implements Serializable {

   @Id
   @GeneratedValue( strategy = GenerationType.AUTO )

   private int sid;
   private String sname;

   public Staff( int sid, String sname ) {
      super( );
      this.sid = sid;
      this.sname = sname;
   }

   public Staff( ) {
      super( );
   }

   public int getSid( ) {
      return sid;
   }

   public void setSid( int sid ) {
      this.sid = sid;
   }

   public String getSname( ) {
      return sname;
   }

   public void setSname( String sname ) {
      this.sname = sname;
   }
}

Crie uma subclasse (classe) para a classe Staff chamada TeachingStaff.java debaixo de com.tutorialspoint.eclipselink.entitypacote. A classe TeachingStaff Entity é mostrada da seguinte forma:

package com.tutorialspoint.eclipselink.entity;

import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;

@Entity
public class TeachingStaff extends Staff {
   private String qualification;
   private String subjectexpertise;

   public TeachingStaff( int sid, String sname, String qualification, String subjectexpertise ) {
      super( sid, sname );
      this.qualification = qualification;
      this.subjectexpertise = subjectexpertise;
   }

   public TeachingStaff( ) {
      super( );
   }

   public String getQualification( ){
      return qualification;
   }
   
   public void setQualification( String qualification ) {
      this.qualification = qualification;
   }

   public String getSubjectexpertise( ) {
      return subjectexpertise;
   }

   public void setSubjectexpertise( String subjectexpertise ){
      this.subjectexpertise = subjectexpertise;
   }
}

Crie uma subclasse (classe) para a classe Staff chamada NonTeachingStaff.java debaixo de com.tutorialspoint.eclipselink.entitypacote. A classe NonTeachingStaff Entity é mostrada da seguinte forma:

package com.tutorialspoint.eclipselink.entity;

import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;

@Entity
public class NonTeachingStaff extends Staff {
   private String areaexpertise;

   public NonTeachingStaff( int sid, String sname, String areaexpertise ) {
      super( sid, sname );
      this.areaexpertise = areaexpertise;
   }

   public NonTeachingStaff( ) {
      super( );
   }

   public String getAreaexpertise( ) {
      return areaexpertise;
   }

   public void setAreaexpertise( String areaexpertise ) {
      this.areaexpertise = areaexpertise;
   }
}

Persistence.xml

O arquivo Persistence.xml contém as informações de configuração do banco de dados e as informações de registro das classes de entidade. O arquivo xml é mostrado da seguinte forma:

<?xml version="1.0" encoding = "UTF-8"?>
<persistence version = "2.0" xmlns = "http://java.sun.com/xml/ns/persistence"
   xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance" 
   xsi:schemaLocation = "http://java.sun.com/xml/ns/persistence 
   http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">

   <persistence-unit name = "Eclipselink_JPA" transaction-type = "RESOURCE_LOCAL">
      <class>com.tutorialspoint.eclipselink.entity.Staff</class>
      <class>com.tutorialspoint.eclipselink.entity.NonTeachingStaff</class>
      <class>com.tutorialspoint.eclipselink.entity.TeachingStaff</class>
      
      <properties>
         <property name = "javax.persistence.jdbc.url" value = "jdbc:mysql://localhost:3306/jpadb"/>
         <property name = "javax.persistence.jdbc.user" value = "root"/>
         <property name = "javax.persistence.jdbc.password" value = "root"/>
         <property name = "javax.persistence.jdbc.driver" value = "com.mysql.jdbc.Driver"/>
         <property name = "eclipselink.logging.level" value = "FINE"/>
         <property name = "eclipselink.ddl-generation" value="create-tables"/>
      </properties>
      
   </persistence-unit>
</persistence>

Classe de serviço

As classes de serviço são a parte de implementação do componente de negócios. Crie um pacote em‘src’ pacote chamado ‘com.tutorialspoint.eclipselink.service’.

Crie uma classe chamada SaveClient.javano pacote fornecido para armazenar os campos de classe Staff, TeachingStaff e NonTeachingStaff. A classe SaveClient é mostrada da seguinte forma:

package com.tutorialspoint.eclipselink.service;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

import com.tutorialspoint.eclipselink.entity.NonTeachingStaff;
import com.tutorialspoint.eclipselink.entity.TeachingStaff;

public class SaveClient {
   public static void main( String[ ] args ) {
      EntityManagerFactory emfactory = Persistence.createEntityManagerFactory( "Eclipselink_JPA" );
      EntityManager entitymanager = emfactory.createEntityManager( );
      entitymanager.getTransaction( ).begin( );

      //Teaching staff entity 
      TeachingStaff ts1 = new TeachingStaff(1,"Gopal","MSc MEd","Maths");
      TeachingStaff ts2 = new TeachingStaff(2, "Manisha", "BSc BEd", "English");
      
      //Non-Teaching Staff entity
      NonTeachingStaff nts1 = new NonTeachingStaff(3, "Satish", "Accounts");
      NonTeachingStaff nts2 = new NonTeachingStaff(4, "Krishna", "Office Admin");

      //storing all entities
      entitymanager.persist(ts1);
      entitymanager.persist(ts2);
      entitymanager.persist(nts1);
      entitymanager.persist(nts2);

      entitymanager.getTransaction().commit();
      entitymanager.close();
      emfactory.close();
   }
}

Após a compilação e execução do programa acima, você receberá notificações no painel do console do Eclipse IDE. Para saída, verifique o ambiente de trabalho MySQL da seguinte maneira:

Aqui, as três tabelas são criadas e o Staff tabela contém registros nulos.

O resultado de TeachingStaff em um formato tabular é mostrado como segue:

Sid Qualificação Sname Experiência do assunto
1 MSC MED Gopal Matemáticas
2 BSC BED Manisha Inglês

A tabela acima TeachingStaff contém campos de Entidades Staff e TeachingStaff.

O resultado de NonTeachingStaff em um formato tabular é mostrado como segue:

Sid Experiência da área Sname
3 Contas Satish
4 Admin de escritório Krishna

A tabela acima NonTeachingStaff contém campos de Entidades Staff e NonTeachingStaff.