viernes, 31 de julio de 2015

Mapeo complejo JPA de tablas relacionadas - IV

FICHERO PERSISTENCE.XML

He aquí el fichero Persistence. He utilizado la implementación de Hibernate para JPA.

No tiene más dificultad, si acaso un par de precisiones:
  1. Poned las clases con la ruta correspondiente que hayáis creado en vuestra aplicación; en mi caso las clases están creadas en el paquete main.models. 
  2. Poned en el username el usuario de vuestra base de datos mysql. El password y url idem de idem.

<?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="NominaJPA">
      <provider>org.hibernate.ejb.HibernatePersistence</provider>
      <class>main.models.Datosprofesionales</class>
      <class>main.models.Empleado</class>
      <class>main.models.Nomina</class>
      <properties>
          <property name="hibernate.connection.username" value="tu_Usuario"/>
          <property name="hibernate.connection.password" value="tu_password"/>
          <property name="hibernate.connection.url" value="jdbc:mysql://localhost:3306/nominaDB"/>
          <property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver"/>
          <property name="hibernate.hbm2ddl.auto" value="update" />
          <!-- Para ver las operaciones sql que se van realizando lo pondríamos en true -->
         <property name="hibernate.show_sql" value="false" />      
      </properties>
   </persistence-unit>
</persistence>


Con esto, tendremos configurada nuestra capa de persistencia. Lo siguiente será crear los ficheros DAO para realizar un adecuado aislamiento entre la capa de persistencia y la de negocio.

Continuará...

jueves, 30 de julio de 2015

Mapeo complejo JPA de tablas relacionadas - III

EXPLICACIÓN DEL MAPEO JPA

Para empezar, decir que es conveniente la anotación @table (name="") porque así nuestras entities pueden tener diferente nombre que las tablas. Soy partidario de esta práctica anotación.
Las columnas han sido mapeadas de la forma habitual, con @Column. Cuando el nombre del atributo de la clase java coincide con el nombre de la columna de la tabla mapeada no es necesario utilizar la etiqueta column. Sin embargo, considero muy útil y conveniente poner siempre el name de la columna mapeada, ya que nos permite modificar en el futuro el atributo sin ocasionar problemas con la base de datos.
Las clases han mapeado el @Id con strategy Identity. Ello es debido a que las tablas se han mapeado con la propiedad AutoIncrement; con esa anotación las tablas gestionan por ellas mismas el valor del id, liberándonos de esa tarea. Los ids han sido creados como long, cuyo equivalente en mysql es BigInt.
El trabajo verdaderamente importante es el mapeo de las relaciones entre las tablas. Como hemos definido antes, el objeto "empleado" está mapeado en dos tablas en las bases de datos, "empleados" y "datosprofesionales". Por lo tanto, ambas tablas deberán estar unidas en una relación @OneToOne bilateral.
Recordemos que, en la relación @OneToOne bilateral establece una relación en la cual cada objeto de una clase tiene relación con uno y solo un objeto de la otra clase, y viceversa. Una de las clases es "dueña" de la relación, lo cual significa que esa clase tendrá una referencia (la id) de la otra clase. Y esa referencia será mapeada en la tabla, en una columna que se añadirá. En la otra clase, la "referenciada", no añadirá ninguna columna a la tabla, pero el objeto tendrá referencia al objeto de la clase "dueña".
El mapeo de las referencias de las otras clases consiste en crear una propiedad del tipo de la clase mapeada, la cual empleará JPA para obtener la referencia id de ese objeto. Ese id será almacenado en el objeto relacionado.
Así pues:
Empleado, la clase "dueña", añade la propiedad private Datosprofesionales profs y guardará la columna en tablas mediante @JoinColumn. El dato guardado en la columna será la id del objeto Datosprofesionales. Y por otro lado, Datosprofesionales, añade la propiedad private Empleado idEmpleado  con mappedBy=profs, lo cual generará una referencia al id del objeto Empleado al cual va unida.
El siguiente mapeo será el de la clase Nominas hacia Empleado y Datosprofesionales. El mapeo de Nominas hacia Empleado es un @ManyToOne bilateral, lo cual significa que un objeto empleado puede tener relación con  varios objetos nomina, mientras que un objeto nomina solo puede tener relación un objeto empleado; y desde ambos deben poder accederse: la nómina debe poder acceder a los datos del empleado, y el empleado debe poder acceder a sus nóminas.
El mapeo de Nominas hacia Datosprofesionales es @ManyToOne unilateral. Cada objeto Nomina tiene relación con un solo objeto Datosprofesionales y puede acceder a esos datos porque tiene referencia. Mientras que un objeto Datosprofesionales no accede directamente a la relación con los objetos Nomina.
La clase Nominas es la clase "dueña" de las relaciones, y por ello mediante @JoinColumn añade dos columnas en su tabla con las cuales referenciada las relaciones con los otros objetos.
Al igual en la relación @OneToOne, la relación @ManyToOne añade propiedades de los objetos referenciados, en nuestro caso private Empleado idEmpleado y private Datosprofesionales idDatosProfesionales; ambas serán referencias id a los objetos correspondientes.
 Por otra parte, en el caso de Datosprofesionales no procede ningún mapeo porque era unilateral. Para nosotros no tiene utilidad que desde datos profesionales podamos acceder a las nóminas.







































En el caso de Empleados, si hay que mapear por la relación es bilateral. Empleados debe mapear @OneToMany, ya que un objeto Empleado puede tener varios objetos Nomina. Sin embargo, en este caso, hablamos de mappedBy. No se creará ninguna columna en la tabla empleados. Pero la referencia a Nomina no será un objeto Nomina, sino un private List<Nomina>nominas; esto es así porque puede haber varios objetos Nomina referenciados. Desde Empleado y mediante el List<Nomina> podremos acceder a todos los objetos Nomina referenciados.
Continuaremos con el fichero persistence.xml ...

lunes, 27 de julio de 2015

Mapeo complejo JPA de tablas relacionadas - II

2.- Mapeo de la tabla Datosprofesionales

@Entity
@Table(name="datosprofesionales")
public class Datosprofesionales implements Serializable {
    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(name="id_datosprofesionales")
    private String idDatosprofesionales;
    // relacion con la tabla empleado
    @OneToOne(mappedBy="profs")
    private Empleado idEmpleado;
    // informacion sobre el trabajador
    // categoria profesional
    @Column(name="categoria",nullable=false)
    private String categoria;
    // puesto
    @Column(name="tipo",nullable=false)
    private String tipo;
    // informacion sobre el centro de trabajo
    @Column(name="centro",nullable=false)
    private String centro;
    @Column(name="direccion",nullable=false)
    private String direccion;
    @Column(name="localidad",nullable=false)
    private String localidad;

    public Datosprofesionales() {
    }
    public Datosprofesionales(String categoria, String tipo, String centro, String direccion, String localidad) {
            this.categoria = categoria;
            this.tipo = tipo;
            this.centro = centro;
            this.direccion = direccion;
            this.localidad = localidad;
    }
    // AÑADIR GETTERS AND SETTERS
}

3.- Mapeo de la tabla Nomina

@Entity
@Table(name="nominas")
public class Nomina implements Serializable {
    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(name="id_nominas")
    private long idNominas;
    @ManyToOne
    @JoinColumn(name="id_empleado",nullable=false)
    private Empleado idEmpleado;
    @ManyToOne
    @JoinColumn(name="id_datosprofesionales",nullable=false)
    private Datosprofesionales idDatosProfesionales;
    // periodo (mes) correspondiente a la nomina
    @Column(name="periodo",nullable=false)
    private int periodo;
    // conceptos salariales de remuneracion bruta
    @Column(name="sueldo",nullable=false)
    private float sueldo;
    @Column(name="complemento")
    private float complemento;
    // conceptos retencion fiscal
    @Column(name="porc_irpf",nullable=false)
    private float porcIrpf;
    @Column(name="ret_irpf")
    private float retIrpf;
    // conceptos retencion seg.soc.
    @Column(name="porc_ss",nullable=false)
    private float porcSs;
    @Column(name="ret_ss")
    private float retSs;
    // neto a pagar de la nomina
    @Column(name="neto",nullable=false)
    private float neto;

    public Nomina() {
    }
    public Nomina(Empleado idEmpleado, Datosprofesionales idDatosProfesionales, int periodo, float sueldo, float complemento, float porcIrpf, float retIrpf, float porcSs, float retSs, float neto) {
            this.idEmpleado = idEmpleado;
            this.idDatosProfesionales = idDatosProfesionales;
            this.periodo = periodo;
            this.sueldo = sueldo;
            this.complemento = complemento;
            this.porcIrpf = porcIrpf;
            this.retIrpf = retIrpf;
            this.porcSs = porcSs;
            this.retSs = retSs;
            this.neto = neto;
    }
    @Override
    public String toString() {
            return "Nomina de "+idEmpleado.getNombre()+" - Salario Bruto: "+(getSueldo()+getComplemento())+" - Retenciones: "+(getRetIrpf()+getRetSs())+" - Neto a cobrar: "+getNeto();
    }
            // AÑADIR GETTERS AND SETTERS

}
Continuará...

miércoles, 22 de julio de 2015

Mapeo complejo JPA de tablas relacionadas - I

Hola de nuevo, jabatos:

En este nuevo ejemplo, vamos a realizar una práctica de JPA con más complejidad. El objeto será conseguir el adecuado funcionamiento e interrelación de tres tablas diferentes. Para ello propongo realizar el mapeo de una hipotética aplicación de nóminas. 
La arquitectura y tecnologías del proyecto serán las siguientes:
·         JavaSE 1.7
·         Eclipse
·         MySql 5
·         HibernateJPA 2.0

En un análisis simple, podemos observar que en una nómina aparecen dos objetos "físicos" mapeables: por un lado el empleado en sí, y por otro lado el pago de la nómina del mes correspondiente. Eso implica que cada trabajador tendrá una nómina cada mes, y que en cada nómina aparece un trabajador. Cada trabajador tendrá sus datos personales y datos profesionales. 
Con esa información, y con fines didácticos, contamos con la siguiente información de base de datos.En la base de datos mysql tenemos las siguientes tres tablas en la DDBB "nominaDB":

Contando con esta información, y analizando las relaciones que puede haber entre las tres tablas, procedemos a confeccionar nuestros ficheros models JPA, con sus correspondientes anotaciones.


MAPEO JPA DE LA TABLAS

1.- Mapeo de la tabla empleados

@Entity
@Table(name="empleados")
public class Empleado implements Serializable {
    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(name="id_empleados")
    private long idEmpleados;
    // relacion con la tabla datosProfesionales
    @OneToOne(cascade={CascadeType.PERSIST,CascadeType.REMOVE},orphanRemoval=true)
    @JoinColumn(name="id_datosprofesionales")
    private Datosprofesionales profs;
    // datos del empleado
    @Column(name="nombre",nullable=false)
    private String nombre;
    @Column(name="dni",nullable=false)
    private String dni;
    @Column(name="segsocial",nullable=false)
    private String segsocial;
    // datos de la direccion del empleado
    @Column(name="direccion",nullable=false)
    private String direccion;
    @Column(name="localidad",nullable=false)
    private String localidad;
    @Column(name="codpostal",nullable=false)
    private String codpostal;
    // datos familiares del empleado y fiscalidad
    @Column(name="situacionfamiliar",nullable=false)
    private int situacionfamiliar;
    @Column(name="num_hijos",nullable=false)
    private int numHijos;
    @Column(name="retencion",nullable=false)
    private float retencion;
    // datos bancarios del empleado
    @Column(name="iban")
    private String iban;
    // relacion con la tabla Nomina
    // esta relacion no se mapea en DDBB
    @OneToMany(mappedBy="idEmpleado", fetch = EAGER)
    private List<Nomina>nominas;

    public Empleado() {
    }      
    public Empleado(Datosprofesionales profs, String nombre, String dni, String segsocial, String direccion, String localidad, String codpostal, int situacionfamiliar, int numHijos, float retencion, String iban) {
            this.profs = profs;
            this.nombre = nombre;
            this.dni = dni;
            this.segsocial = segsocial;
            this.direccion = direccion;
            this.localidad = localidad;
            this.codpostal = codpostal;
            this.situacionfamiliar = situacionfamiliar;
            this.numHijos = numHijos;
            this.retencion = retencion;
            this.iban = iban;
    }
    @Override
    public String toString() {
            return "Empleado: "+getNombre()+" - DNI: "+getDni()+" - Puesto trabajo: "+getProfs().getTipo()+" - Centro: "+getProfs().getCentro();
    }
    // AÑADIR GETTERS AND SETTERS
}

Continuará...