jueves, 24 de mayo de 2012

Claves Compuestas JPA

Aquí se muestra un ejemplo de como manejar las claves compuestas en JPA, para este caso se usa de inicio las anotaciones @IdClass y @EmbeddedId.

La estructura de la tabla es la siguiente, la tabla pue`e quedar mas completa añadiendo o eliminando campos pero solo es para mostrar el uso de la llave compuesta
Aquí se puede ver la clave compuesta con los campos folio y serie. Creamos la clase que representa la clave compuesta
public class IdFactura implements Serializable{
 private int folio;
 private String serie;
 
 public IdFactura(int folio, String serie) {
  super();
  this.folio = folio;
  this.serie = serie;
 }
}
Cabe señalar que la clase IdFactura no esta escrita o no se añade alguna anotacion en particular, solo contiene las propiedades y constructores, ahora se genera la entidad Factura
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.IdClass;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;

import org.dracof.jpa.IdFactura;

@Entity
@Table (name="Factura")
@IdClass (IdFactura.class)
public class Factura implements Serializable {
 @Id
 @Column
 private int folio;
 
 @Id
 @Column
 private String serie;
 
 @Column
 private String emisor;
 
 @Column
 @Temporal (TemporalType.DATE)
 private Date fecha;
 
 //setters & getters
}
Aquí escribimos @IdClass (IdFactura.class) para indicar que haremos uso de la clase IdFactura para representar a la llave compuesta Se genera el cliente para realizar la inserción y la consulta
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

import org.dracof.jpa.entities.Factura;

public class Cliente {
 public static void main(String[] args) {
  
  int folio = 1;
  String serie = "B";
  
  Cliente cliente = new Cliente();
  cliente.generaFactura(folio, serie);
  cliente.consultaFactura(folio, serie);
 }
 
 private void generaFactura(int folio, String serie) {

  System.out.println("Insertando Factura...");
  EntityManagerFactory emf = null;
  EntityManager em = null;
  Factura factura = new Factura();

  factura.setFolio(folio);
  factura.setSerie(serie);
  factura.setEmisor("Empresa X");
  factura.setFecha(null);
  try {
   emf = Persistence.createEntityManagerFactory("unitPersistence");
   em  = emf.createEntityManager();
   
   em.getTransaction().begin();
   em.persist(factura);
   em.getTransaction().commit();
   System.out.println("Factura insertada correctamente");
  } catch (Exception e) {
   System.out.println("Existe un error al insertar factra");
   em.getTransaction().rollback();
   e.printStackTrace();
  } finally {
   em.close();
   emf.close();
  }
 }
 
 private void consultaFactura(int folio, String serie) {
  System.out.println("Consultando Factura...");

  EntityManagerFactory emf = null;
  EntityManager em = null;
  
  IdFactura idFactura = new IdFactura(folio, serie);
  try {
   emf = Persistence.createEntityManagerFactory("unitPersistence");
   em  = emf.createEntityManager();
   
   
   Factura factura = em.find(Factura.class, idFactura);
   System.out.println("Folio:  " + factura.getFolio());
   System.out.println("Serie:  " + factura.getSerie());
   System.out.println("Emisor: " + factura.getEmisor());
   System.out.println("Fecha:  " + factura.getFecha());
  } catch (Exception e) {
   e.printStackTrace();
  } finally {
   em.close();
   emf.close();
  }
 }
}
Y vemos el resultado de ejecutar el cliente
Insertando Factura...
Factura insertada correctamente
Consultando Factura...
Folio:  1
Serie:  B
Emisor: Empresa X
Fecha:  null
Ahora se realizan algunos cambios para hacer la prueba con @EmbeddableId Se modifica la clase IdFactura de la siguiente forma
@Embeddable
public class IdFactura implements Serializable {
 @Column
 private int folio;
 
 @Column
 private String serie;
 
 public IdFactura() {
 }
 
 public IdFactura(int folio, String serie) {
  super();
  this.folio = folio;
  this.serie = serie;
 }

 public int getFolio() {
  return folio;
 }

 public String getSerie() {
  return serie;
 }

//en este caso omiti los setters para convertir la clase en inmutable
}
Se nota que ahora la clase IdFactura se anota con @Embeddable y los campos folio y serie ahora contienen @Column, hay que recordar que como los campos serie y folio se llaman igual que los campos de la tabla podemos omitir el parámetro name de Column
import javax.persistence.Column;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.IdClass;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;

import org.dracof.jpa.IdFactura;

@Entity
@Table (name="Factura")
public class Factura implements Serializable {

 @EmbeddedId
 private IdFactura idFactura;
 
 @Column
 private String emisor;
 
 @Column
 @Temporal (TemporalType.DATE)
 private Date fecha;

 public IdFactura getIdFactura() {
  return idFactura;
 }

 public void setIdFactura(IdFactura idFactura) {
  this.idFactura = idFactura;
 }

 public String getEmisor() {
  return emisor;
 }

 public void setEmisor(String emisor) {
  this.emisor = emisor;
 }

 public Date getFecha() {
  return fecha;
 }

 public void setFecha(Date fecha) {
  this.fecha = fecha;
 }
}
Observamos que ahora para representar la llave compuesta dentro de Factura se usa @EmbeddedId y usamos IdFactura como una propiedad. El cliente se modifica ligeramente quedando
public class Cliente {
 public static void main(String[] args) {
  ...
 }
 
 private void generaFactura(int folio, String serie) {
  ...
  Factura factura = new Factura();
  IdFactura idFactura = new IdFactura(folio, serie);
  
  factura.setIdFactura(idFactura);
  factura.setEmisor("Empresa X");
  factura.setFecha(null);
  ...
 }
 
 private void consultaFactura(int folio, String serie) {

  // no sufre cambios
 }
}
Obteniendo el mismo resultado
Insertando Factura...
Factura insertada correctamente
Consultando Factura...
Folio:  1
Serie:  B
Emisor: Empresa X
Fecha:  null
Ahora realizamos el ejercicio usando solo XML, entonces borramos todas las anotaciones y la configuración del XML usando id-class y embeddable respectivamente
<entity-mappings>
    <entity class="org.dracof.jpa.entities.Factura">
     <table name="Factura"/>
     <id-class class="org.dracof.jpa.IdFactura"/>
     <attributes>
      <id name="folio">
       <column/>
      </id>
      <id name="serie">
       <column/>
      </id>
      <basic name="emisor">
       <column/>
      </basic>
      <basic name="fecha">
       <temporal>DATE</temporal>
       <column/>
      </basic>
     </attributes>
    </entity>
</entity-mappings>
y
<entity-mappings>
    <embeddable class="org.dracof.jpa.IdFactura">
     <attributes>
      <basic name="folio">
       <column/>
      </basic>
      <basic name="serie">
       <column/>
      </basic>
     </attributes>
    </embeddable>
    <entity class="org.dracof.jpa.entities.Factura">
     <table name="Factura"/>
     <attributes>
      <embedded-id name="idFactura"/>
      <basic name="emisor">
       <column/>
      </basic>
      <basic name="fecha">
       <temporal>DATE</temporal>
       <column/>
      </basic>
     </attributes>
    </entity>
</entity-mappings>
La estructura del proyecto quedo como sigue
Suerte.

2 comentarios: