Referencia JPA

RECU-0176 (Recurso Referencia)

Descripción

Java Persistence API, más conocida por su sigla JPA, es la API de persistencia desarrollada para la plataforma Java EE e incluida en el estándar EJB3. Esta API busca unificar la manera en que funcionan las utilidades que proveen un mapeo objeto-relacional. El objetivo que persigue el diseño de esta API es no perder las ventajas de la orientación a objetos al interactuar con una base de datos, como sí pasaba con EJB2, y permitir usar objetos regulares (conocidos como POJOs).

JPA es un modelo basado en POJO persistencia estándar para el ORM. Es parte de la especificación de EJB 3 y sustituye a beans de entidad. Los beans de entidad se definen como parte de la especificación de EJB 2.1 y no habían logrado impresionar a la industria como una solución completa para la persistencia de varias razones

  • Los beans de entidad son componentes pesados y están estrechamente unidos a un servidor Java EE. Esto hace que sean menos adecuados que POJOs ligeros, que son más convenientes para su reutilización.
  • Los beans de entidad son difíciles de desarrollar y desplegar.
  • Los beans de entidad BMP te obligan a utilizar JDBC, mientras que los beans de entidad CMP son altamente dependientes en el servidor de Java EE para su configuración y la declaración de ORM. Estas restricciones afectan el funcionamiento de la aplicación.

JPA toma las mejores ideas de las tecnologías de la persistencia de otros. Se define un modelo de persistencia estándar para todas las aplicaciones Java. JPA puede ser utilizado como la solución tanto para la persistencia de Java SE y Java EE.

JPA utiliza anotaciones de metadatos y / o los archivos del descriptor XML para configurar el mapeo entre objetos Java en el ámbito de aplicación y las tablas de la base de datos relacional. JPA es una solución ORM completa y soporta la herencia y polimorfismo. También se define un lenguaje de consulta como SQL , JPQL (Java Persistence Query Language), que es diferente de EJB-QL (EJB Query Language), el lenguaje utilizado por los beans de entidad.

Con JPA, se puede conectar en cualquier proveedor de persistencia que implementa la especificación de la JPA en lugar de utilizar cualquier proveedor de persistencia que venga por defecto con el contenedor Java EE. Por ejemplo, el servidor de aplicaciones GlassFish, suministrado por Oracle, como proveedor que usa como motor predeterminado de persistencia TopLink Essentials. Pero usted podría elegir usar Hibernate como proveedor de persistencia mediante la inclusión de todos los archivos JAR necesarios en su aplicación.

¿Que es una Entidad?

La entidad no es una cosa nueva en la gestión de datos. De hecho, las entidades han estado alrededor de muchos lenguajes de programación y, ciertamente, más de Java. Fueron introducidos por primera vez por Peter Chen en su artículo seminal sobre el modelado entidad-relación .Describió entidades como las cosas que tienen atributos y relaciones. La expectativa era que los atributos y las relaciones se persistían en una base de datos relacional.

Incluso ahora, la definición sigue siendo válida. Una entidad es esencialmente un sustantivo, o una agrupación de estado asociados juntos como una sola unidad. Se podrá participar en las relaciones a cualquier número de otras entidades en una serie de formas estándar. En el paradigma orientado a objetos, nos gustaría añadir un comportamiento a la misma y lo llaman un objeto. En JPA, cualquier objeto definido por la aplicación puede ser una entidad, así que la pregunta importante podría ser esto: ¿Cuáles son las características de un objeto que se ha convertido en una entidad?

Persistencia

La primera y más básica característica de las entidades es que son persistentes. En general, esto sólo significa que puedan hacerse persistentes. Más concretamente, significa que su estado se puede almacenar en una base de datos y se puede acceder en otro momento, tal vez mucho después del final del proceso que lo creó.

Podríamos llamarlos objetos persistentes, y muchas personas lo hacen, pero no es técnicamente correcto. Estrictamente hablando, un objeto persistente se vuelve persistente en el momento en que se crea una instancia en la memoria. Si un objeto persistente existe, entonces, por definición, ya es persistente.

Una entidad es persistente, ya que se puede crear en un almacén persistente. La diferencia es que no se persistió de forma automática, y que para que tenga una representación duradera en la aplicación activa debe invocar un método de la API para iniciar el proceso. Esta distinción es importante porque deja el control sobre la persistencia en manos de la aplicación. Esta misma cuenta con la la flexibilidad para manipular los datos y realizar la lógica de negocio de la entidad, por lo que es persistente sólo cuando la aplicación decide que es el momento adecuado. La lección es que las entidades pueden ser manipuladas sin necesariamente persistentes, y es la aplicación que decide si son o no.

Identidad

Al igual que cualquier otro objeto Java, una entidad tiene una identidad de objeto, pero cuando existe en la base de datos también posee una identidad persistente. Esta identidad persistente, o un identificador, es la clave que identifica de forma única una instancia de la entidad y la distingue de todas las otras instancias de la misma entidad.

Una entidad tiene un identidad persistente cuando existe una representación de él en la base de datos, es decir, una fila en una tabla de una base de datos . Si no está en la base de datos , a pesar de que la entidad en memoria puede tener su identidad en un campo, no tiene una identidad persistente. El identificador de la entidad, entonces, es equivalente a la clave principal en la tabla de base de datos que almacena el estado de la entidad.

Transaccionalidad

Las entidades son lo que podríamos llamar cuasi-transaccional. Aunque se pueden crear, actualizar y eliminar en cualquier contexto, estas operaciones se realizan normalmente en el contexto de una transacción debido a que una transacción es necesaria para que los cambios que sean comprometidos en la base de datos. Los cambios son realizados en la base de datos ya sean éxito o fracaso , por lo que la visión persistente de una entidad de hecho debe ser transaccional.

En la memoria, es una historia ligeramente diferente en el sentido de que las entidades pueden ser modificadas sin que los cambios sean persistidos. Incluso cuando se enlistaron en una transacción, se puede dejar indefinido o en un estado inconsistente en el caso de un retroceso o el fracaso de transacción. Las entidades que están en la memoria son simples objetos Java que obedecen todas las reglas y restricciones que se aplican por la Virtual Java Machine (JVM) a otros objetos de Java.

Granularidad

Por último, también podemos aprender algo acerca de lo que son las entidades al describir lo que no lo son. No son primitivos, envoltorios primitivos, o objetos integrados con el estado de una sola dimensión. Estos no son más que escalares y no tienen ningún significado semántico inherentes a una aplicación. Una cadena, por ejemplo, es demasiado fina para ser un objeto entidad, ya que no tiene ningún dominio específico . Por el contrario, una cadena esta bien adaptado y a menudo muy utilizado como un tipo de un atributo de entidad y le da un significado de acuerdo con el atributo entidad que lo está escribiendo.

Las entidades que están destinadas a ser objetos de grano fino que tienen un conjunto de estado global, el cual es normalmente almacenado en un solo lugar, como una fila de una tabla, y suelen tener relaciones con otras entidades. En el sentido más general, son objetos de dominio de negocio que tienen un significado específico a la aplicación que tiene acceso a ellos.

Si bien es cierto que las entidades pueden ser definidas de manera exagerada a ser tan fina como almacenamiento de una sola cadena o de grano grueso suficiente para contener un valor de 500 columnas de datos, las entidades de la JPA estaban destinadas a ser definitivamente el extremo más pequeño del espectro de la granularidad. Idealmente, las entidades deben ser diseñados y definidos como objetos bastante ligeros, de un tamaño comparable al de la media del objeto de Java.

Entity Manager

Una llamada a la API específica necesita ser invocada ante un entidad que realmente persiste la base de datos. De hecho,son necesarias llamadas separadas a la API para realizar muchas de las operaciones en las entidades. Esta API está implementada por el administrador de la entidad y encapsuladas casi totalmente dentro de una única interfaz llamada EntityManager.

Cuando un EntityManager obtiene la referencia a una entidad, ya sea porque se le pasa como argumento en la llamada al método o porque se lee de la base de datos, ese objeto se dice que esta manejado por el EntityManager. El conjunto de instancias manejadas por el EntityManager se considera el contexto de persistencia. Solo una instancia Java con la misma identidad de la persistencia puede existir en un contexto de persistencia al mismo tiempo.

Los EntityManager se configuran para ser capaces de persistir o administrar tipos específicos de objetos, leer y escribir en una base de datos, y ser implementados por un proveedor de persistencia en particular. Es el proveedor que suministra el motor de aplicación para todo el respaldo de Java Persistence API, desde el EntityManager hasta la implementación de las clases de consulta y la generación SQL.

Todos los EntityManagers provienen de fábricas tipo EntityManagerFactory . La configuración de un EntityManager es formateado por la EntityManagerFactory que lo creó, sin embargo se define por separado como una unidad de persistencia.

Una unidad de persistencia dicta , ya sea implícita o explícitamente, los valores y clases de entidad que utilizan todos los EntityManagers obtenidos a partir de la instancia única del EntityManagerFactory asociada a esa unidad de persistencia. Existe, por tanto, una correspondencia uno a uno entre una unidad de persistencia y su EntityManagerFactory concreto.

Las unidades de persistencia permiten la diferenciación de un EntityManagerFactory de otro. Esto le da el control de la aplicación sobre cualquier configuración o unidad de persistencia que se utilizará para operar con una entidad en particular.

Obteniendo un EntityManager

Un EntityManager es siempre obtenido desde un EntityManagerFactory. La factoría desde la que es obtenido determina la configuración de los parámetros que gobiernan la operación. El método estático createEntityManagerFactory() en la clase de persistencia devuelve la para el nombre de la unidad de persistencia especificado. Por ejemplo:

EntityManagerFactory emf = Persistence.createEntityManagerFactory("EmployeeService");

El nombre especifico de la unidad de persistencia “EmployeeService” se pasa al método createEntityManagerFactory() identifica la configuración unidad de persistencia dada que determina muchas cosas como los parametros de conexión que los EntityManagers son generados desde esta factoría cuando se conectan a la base de datos. Ahora tenemos una factoría, pueden fácilmente obtenerse un EntityManager a partir de ella. Como el siguiente ejemplo:

EntityManager em = emf.createEntityManager();

Persistiendo una Entidad

La persistencia de una entidad es la operación de tomar una entidad transitoria, o una que todavía no tienen ninguna representación persistente en la base de datos, y almacenar su estado para que pueda ser recuperado más tarde. Esto es realmente la base de la persistencia de creación de estado, que puede durar más que el proceso que lo creó. Vamos a comenzar usando el gestor de la entidad que persista una instancia de Empleado. Aquí está un ejemplo de código que hace precisamente eso:

Employee emp = new Employee(158);
em.persist(emp);

La primera línea en este segmento de código es simplemente la creación de una instancia del empleado que queremos persistir. El empleado es sólo una instancia regular de objeto Java .La siguiente línea utiliza el administrador de la entidad para que persista la entidad. Llamar al método persist() es todo lo que se requiere para iniciar lo que se persiste en la base de datos. Si el administrador de la entidad se encuentra con un problema al hacer esto, entonces elevará una PersistenceException sin marcar. Cuando el método persiste() devuelve un valor de retorno, emp tendrá que convertirse en una entidad gestionada dentro del contexto de la persistencia del EntityManager

public Employee createEmployee(int id, String name, long salary) {
  Employee emp = new Employee(id);
  emp.setName(name);
  emp.setSalary(salary);
  em.persist(emp);
  return emp;
}

Buscando una entidad

Una vez que una entidad está en la base de datos, lo siguiente que uno normalmente quiere hacer es encontrarla de nuevo. En realidad sólo hay una línea que tenemos que mostrar, llamando al método find

Employee emp = em.find(Employee.class, 158);

Estamos pasando como parámetros la clase de la entidad que se busca (en este ejemplo, estamos buscando una instancia de los empleados) y la clave de identificación o primaria que identifica a la entidad en particular (en nuestro caso se quiere encontrar la entidad que acabamos de crear en el punto anterior). Esta es toda la información necesaria para que el EntityManager pueda encontrar la instancia en la base de datos, y cuando la llamada termina, el empleado que se devuelve sea gestionado como una entidad, lo que significa que existirá en el contexto de persistencia actual asociado con el entidad gerente. ¿Qué sucede si el objeto se ha eliminado o si se suministra el identificador de mal por accidente? En el caso de que el objeto no se encuentre, entonces el método find() simplemente devuelve null

Eliminando la entidad

La eliminación de una entidad de la base de datos no es tan común como usted podría pensar. Muchas aplicaciones nunca eliminan objetos, o si lo hacen sólo los datos que ya no son válidos . Para eliminar la entidad , la propia entidad debe manejarse, lo que quiere decir que la llamada a la aplicación debe de estar cargada o accedida la entidad y ahora se envía un comando para eliminarla. Esto normalmente genera un problema porque la aplicación que acusó la llamada esta siendo manejada como parte del proceso para determinar que ese era el objeto que quería eliminarse . El ejemplo sería el siguiente:

Employee emp = em.find(Employee.class, 158);
em.remove(emp);

Transacciones

La situación típica cuando se ejecuta en el entorno de contenedor Java EE es que se utiliza el estándar Java Transaction API (JTA) para el manejo de transacciones. El modelo de transacción cuando se ejecuta en el contenedor asume que la aplicación asegura que un contexto transaccional está presente cuando éste sea necesario. Si una transacción no está presente, entonces o bien la operación de modificación lanza una excepción o el cambio el nunca será persistido en la base de datos.

em.getTransaction().begin();
createEmployee(158, "John Doe", 45000);
em.getTransaction().commit();

Java Persistence Query Language

Definiendo Consultas

JPA posee las interfaces Query y TypedQuery para configurar y ejecutar consultas. La interfaz Query se utiliza para los casos en los que los resultados se esperan que sean de tipo Objeto, y la interfaz TypedQuery se en caso de que los resultados sean ..... La interfaz TypeQuery extiende a Query, por lo que una consulta con tipo puede ser tratada como si fuera una consulta sin tipo pero no al revés. Una implementación de la interfaz apropiada para una consulta dada es obtenida a través de uno de los métodos factoría de la interfaz del EntityManager. La elección de un método depende del tipo de la consulta y si la consulta ha sido fijada de antemano y si inflexible resultados de los deseados.

Consultas Dinámicas

Una consulta se define dinámicamente pasando la cadena de la consulta JPQL y el tipo de resultado esperado al método createQuery() de la interfaz EntityManager. El tipo de resultado puede ser omitido para obtener consultas sin tipo. No existen restricciones a la hora de definir consultas. La habilidad de construir una cadena en tiempo de ejecución y utilizarlo para una definición de la consulta es útil, especialmente para aplicaciones donde el usuario puede especificar criterios complejos y la forma exacta de la consulta no puede ser conocida con anticipación. Como se señaló anteriormente, además de consultas de cadena dinámica, también JPA es compatible con una API de criterios para crear consultas dinámicas con objetos Java.

Una cuestión a considerar con cadena de consultas dinámicas, sin embargo, es el costo de la traducción de JPQL en SQL para su ejecución. Un motor de consulta típica tendrá que analizar la cadena de JP QL en una sintaxis árbol, obtener los metadatos de mapeo objeto-relacional para cada entidad en cada expresión, y luego generar el SQL equivalente. Para las aplicaciones de muchas consultas , el costo de procesamiento de la consulta dinámica puede ser un problema importante de rendimiento.

@Stateless
public class QueryServiceBean implements QueryService {
   @PersistenceContext(unitName="DynamicQueries")
   EntityManager em;

   public long queryEmpSalary(String deptName, String empName) {
      String query = "SELECT e.salary " +
      "FROM Employee e " +
      "WHERE e.department.name = '" + deptName +
      "' AND " +
      " e.name = '" + empName + "'";
      return em.createQuery(query, Long.class).getSingleResult();
   }
}
Consultas con Nombre

Las consultas con nombre son una poderosa herramienta para la organización de las definiciones de consulta y la mejora de rendimiento de la aplicación. Una consulta con nombre se define mediante la anotación @NamedQuery, que pueden ser puesta en la definición de clase para cualquier entidad. La anotación define el nombre de la consulta, así como el texto de la consulta.

@NamedQuery(name="findSalaryForNameAndDepartment",
            query="SELECT e.salary " +
                  "FROM Employee e " +
                  "WHERE e.department.name = :deptName AND " +
                  " e.name = :empName")

El nombre de la consulta es del ámbito de toda la unidad de persistencia por lo que debe ser único dentro de ese ámbito de aplicación. Esta es una restricción importante a tener en cuenta, como comúnmente se utilizan nombres de consulta como "FindAll" tendrá que ser calificado para cada entidad. Una práctica común es el prefijo el nombre de la consulta con el nombre de la entidad. Por ejemplo, el "findAll" de consulta para los empleados de la entidad se denominará "Employee.findAll".

Debido a que la cadena de consulta se define en la anotación, no pueden ser alterados por la aplicación en tiempo de ejecución. Esto contribuye al rendimiento de la aplicación y ayuda a prevenir el tipo de problemas de seguridad que discutimos . Debido a la naturaleza estática de la cadena de consulta, cualquier criterios adicional que se requiere para la consulta debe ser especificado utilizando parámetros de consulta.

Tipos de Parámetros

JPA es compatible tanto con nombre y parámetros de posición de las consultas JPQL. La métodos de la factoría de consultas del EntityManager devuelven una implementación de la interfaz de consultas (Query interface). Los valores de los parámetros se establecen con el método setParameter () de la interfaz de consultas. Hay tres variantes de este método para ambos , parámetros con nombre y los parámetros de posición.

  • El primer argumento es siempre el nombre de parámetro o un número.
  • El segundo argumento es el objeto que se ha vinculado al parámetro con el nombre.
  • Date y Calendar también requieren un tercer argumento de que especifica si el tipo pasado a JDBC , si es una java.sql.Date, java.sql.Time o java.sql.TimeStamp .
@NamedQuery(name="findEmployeesAboveSal",
            query="SELECT e " +
                  "FROM Employee e " +
                  "WHERE e.department = :dept AND " +
                  " e.salary > :sal")

Esta consulta destaca una de las características interesantes de JPQL en que los tipos de entidad pueden ser utilizados como parámetros. Cuando la consulta se traduce a SQL, necesita las columnas de clave principal que se insertarán en la expresión condicional y se vincularán con los valores de clave principal a partir del parámetro.

Otras Características Principales

Una entidad es un objeto de dominio de persistencia. Normalmente, una entidad representa una tabla en el modelo de datos relacional y cada instancia de esta entidad corresponde a un registro en esa tabla.El estado de persistencia de una entidad se representa a través de campos persistentes o propiedades persistentes. Estos campos o propiedades usan anotaciones para el mapeo de estos objetos en el modelo de base de datos.

Las entidades podrán utilizar campos persistentes o propiedades. Si las anotaciones de mapeo se aplican a las instancias de las entidades, la entidad utiliza campos persistentes, En cambio, si se aplican a los métodos getters de la entidad, se utilizarán propiedades persistentes. Hay que tener en cuenta que no es posible aplicar anotaciones tanto a campos como a propiedades en una misma entidad.

Campos persistentes

Si la entidad utiliza campos persistentes, los accesos se realizan en tiempo de ejecución. Aquellos campos que no tienen anotaciones del tipo javax.persistence.Transient o no han sido marcados como Java transitorio serán persistentes para el almacenamiento de datos. Las anotaciones de mapeo objeto/relación deben aplicarse a los atributos de la instancia.

Propiedades persistentes

Si la entidad utiliza propiedades persistentes, la entidad debe seguir el método de los convenios de componentes JavaBeans. Las propiedades de JavaBean usan métodos getters y setters en cuyo nombre va incluido el atributo de la clase al cual hacen referencia. Si el atributo es booleano podrá utilizarse isProperty en lugar de getProperty. Por ejemplo, si una entidad Customer, utiliza las propiedades de persistencia, supongamos que tiene un atributo privado denominado firsName, la clase definirá los métodos getFirstName y setFirstName para recuperar y establecer el valor de la variable firstName.

Los métodos para la firma de un valor único de propiedades son los siguientes.

Tipo getProperty ()
void setProperty (Tipo tipo)

Tanto los campos persistentes como las propiedades deben utilizar las interfaces de Java independientemente de que la entidad utilice campos o propiedades. Las colecciones posibles son:

  • java.util.Collection
  • java.util.Set
  • java.util.List
  • java.util.Map

Si la entidad utiliza campos persistentes, el tipo en el método anterior debe ser uno de estos tipos de collection. Las variables genéricas de estos tipos también pueden ser utilizadas. Por ejemplo, si la entidad Customer tiene un atributo que contiene un conjunto de números de teléfono, tendrá que tener los siguientes métodos:

Set<PhoneNumber> getPhoneNumbers() {} 
void setPhoneNumbers(Set<PhoneNumber>) {}

Las anotaciones del mapeo objeto/relacional deben aplicarse a los métodos getter. El mapeo de las anotaciones no puede aplicarse a los campos o propiedades anotadas como @Transient o marcadas como transient.

Clases con claves primarias

Una clase con clave primaria debe cumplir los siguientes requerimientos:

  • El modificador de control de acceso de la clase debe ser público
  • Las propiedades de la clave primaria deben ser públicas o protected si se utiliza el acceso a la base de la propiedad.
  • La clase debe tener un constructor público por defecto.
  • La clase debe implementar los métodos hashCode() y equals(Object other)
  • La clase debe ser serializable.
  • Una clave primaria debe representarse y mapearse por campos múltiples o propiedades de la clase de la entidad, o debe representarse y mapearse como una clase embebida.
  • Si la clave primaria está compuesta por varios campos o propiedades, los nombres y tipos de campos de la clave primaria o propiedades en la clave primaria debe coincidir con las de la entidad.
public final class LineItemKey implements Serializable {
    public Integer orderId;
    public int itemId;

    public LineItemKey() {}

    public LineItemKey(Integer orderId, int itemId) {
        this.orderId = orderId;
        this.itemId = itemId;
    }

    public boolean equals(Object otherOb) {
        if (this == otherOb) {
            return true;
        }
        if (!(otherOb instanceof LineItemKey)) {
            return false;
        }
        LineItemKey other = (LineItemKey) otherOb;
        return (
                    (orderId==null?other.orderId==null:orderId.equals
                    (other.orderId)
                    )
                    &&
                    (itemId == other.itemId)
                );
    }

    public int hashCode() {
        return (
                    (orderId==null?0:orderId.hashCode())
                    ^
                    ((int) itemId)
                );
    }

    public String toString() {
        return "" + orderId + "-" + itemId;
    }
}

Relaciones múltiples de la entidad

Hay cuatro tipo de relaciones: uno a uno, uno a muchos, muchos a uno, y muchos a muchos.

Uno a uno: Cada entidad se relaciona con una sola instancia de otra entidad. Por ejemplo, al modelo físico de almacén en el que cada almacén contiene un único artilugio, StorageBin y Widget, deberían tener una relación uno a uno. Las relaciones uno a uno utilizan anotaciones javax.persistence.OneToOne.

Uno a muchos: Una entidad, puede estar relacionada con varias instancias de otras entidades. Una orden de venta (Order), por ejemplo, puede tener varias partidas (LineItem). En la aplicación de la orden, La orden (Order) tendrá una relación uno a muchos con las partidas (LineItem). Las relaciones uno a muchos utilizan anotaciones javax.persistence.OneToMany en los campos o propiedades persistentes.

Muchos a uno: Múltiples instancias de una entidad pueden estar relacionadas con una sola instancia de otra entidad. Esta multiplicidad es lo contrario a la relación uno a muchos. En el ejemplo anterior, desde la perspectiva de la orden de venta (LineItem) la relación con la Orden (Order) es de muchos a uno. Las relaciones muchos a uno utilizan anotaciones javax.persistence.ManyToOne en los campos o propiedades persistentes.

Muchos a muchos: En este caso varias instancias de una entidad pueden relacionarse con múltiples instancias de otras entidades. Por ejemplo, cada curso de una universidad tiene muchos estudiantes, y cada estudiante puede tener varios cursos. Por lo tanto, en una solicitud de inscripción, los cursos y los estudiantes tendrían una relación muchos a muchos. Este tipo de relación utiliza anotaciones javax.persistence.ManyToMany en los campos o propiedades persistentes.

Relaciones y borrado en cascada

Existen entidades que utilizan relaciones con dependencias de relaciones de otra entidad. Por ejemplo, una línea es parte de una orden, y si la orden es eliminada, entonces la línea también debe eliminarse. Esto se llama borrado en cascada. Las relaciones de borrado en cascada se especifican utilizando cascade=REMOVE, elemento que viene en la especificación de las relaciones @OneToOne y @OneToMany. Por ejemplo:

@OneToMany(cascade=REMOVE, mappedBy="customer")
public Set<Order> getOrders() { return orders; }

Trabajar con la JPA

JPA utiliza muchas interfaces y tipos de anotaciones definidas en el paquete de javax.persistence disponible con la versión 5 de Java EE. JPA utiliza las clases de entidad que se asignan a las tablas de la base de datos. Estas clases de entidad se definen en las anotaciones de la JPA. A continuación se muestra la clase de entidad con nombre Employee que corresponde a la tabla Employee de la base de datos del ejemplo

@Entity
@Table(name = "employee")
@NamedQueries({@NamedQuery(name = "Employee.findByEmpId", query = "SELECT e FROM Employee e WHERE e.empId = :empId"), @NamedQuery(name = "Employee.findByEmpFirstname", query = "SELECT e FROM Employee e WHERE e.empFirstname = :empFirstname"), @NamedQuery(name = "Employee.findByEmpLastname", query = "SELECT e FROM Employee e WHERE e.empLastname = :empLastname")})
public class Employee implements Serializable {
        @Id
      @Column(name = "emp_id", nullable = false)
  private Integer empId;
  @Column(name = "emp_firstname", nullable = false)
  private String empFirstname;
  @Column(name = "emp_lastname", nullable = false)
  private String empLastname;

public Employee() {    }
public Employee(Integer empId) {
        this.empId = empId;
}
public Employee(Integer empId, String empFirstname, String empLastname) {
   this.empId = empId;
        this.empFirstname = empFirstname;
        this.empLastname = empLastname;
}
public Integer getEmpId() {
        return empId;
      }
      public void setEmpId(Integer empId) {
        this.empId = empId;
      }
      public String getEmpFirstname() {
        return empFirstname;
}
      public void setEmpFirstname(String empFirstname) {
        this.empFirstname = empFirstname;
}
      public String getEmpLastname() {
        return empLastname;
}
public void setEmpLastname(String empLastname) {
        this.empLastname = empLastname;
}
   /****
*override equals, hashcode and toString methods
*using @Override annotation
******/

Las características de una clase de entidad son los siguientes:

  • La clase de entidad está anotada con la anotación javax.persistence.Entity @Entity
  • Se debe tener un constructor público o sin argumentos y protegido,también puede contener otros constructores.
  • No puede ser declarada final
  • Las clases de entidad pueden extender de otras clases entidad y las clases de no entidad.También es posible la situación inversa
  • Ellos no pueden tener variables de instancia public. Los miembros de la clase deben ser expuestos usando los métodos getter y setter, siguiendo el estilo JavaBean.
  • Clases de entidad, POJOs , en general, no es necesario aplicar las interfaces especiales. Sin embargo, si van a ser pasados como argumentos en la red, entonces se debe implementar la interfaz Serializable

La anotación javax.persistence.Table especifica el nombre de la tabla a la que se asigna esta instancia de la entidad. Los miembros de la clase pueden ser tipos primitivos de Java, las envolturas de los primitivos de Java, tipos enumerados, o incluso de otras clases de enrasado. La asignación a cada columna de la tabla se especifica mediante la anotación javax.persistence.Column. Esta asignación se puede utilizar con campos persistentes, en cuyo caso la entidad utiliza los campos persistentes, así, o con métodos de getter/setter, en cuyo caso la entidad utiliza las propiedades persistentes. Sin embargo, la misma convención se deben seguir para una clase de entidad en particular. Los campos que están anotadas usando javax.persistence.Transient o marcados mediante la anotación transient, no se conservarán en la base de datos.

Cada entidad tiene un identificador de objeto único. Este identificador se utiliza para diferenciar entre los diferentes casos de la entidad en el dominio de aplicación, que corresponde a una clave principal que se define en el cuadro correspondiente. Una clave principal puede ser simple o compuesto. Una clave principal se denota simple utilizando la anotación javax.persistence. Las claves compuestas primaria puede ser una propiedad persistente individual o campo persistente individual de un conjunto de campos o propiedades, deben ser definidos en una clase de clave principal. Las claves compuestas primaria se indican mediante el anotaciones javax.persistence.EmbeddedId y javax.persistence.IdClass. Cualquier clase de clave primaria debe aplicar el hashcode() y equals() métodos.

El ciclo de vida de las entidades de la JPA es administrado por el "entity manager", que es una instancia de javax.persistence.EntityManager. Cada "entity manager" se asocia con un contexto de persistencia. Este contexto puede ser reproducido en todos los componentes de la aplicación o gestionados por la aplicación. El EntityManager pueden ser creado en la aplicación utilizando un EntityManagerFactory como se muestra en el ejemplo

public class Main {
  private EntityManagerFactory emf;
  private EntityManager em;
  private String PERSISTENCE_UNIT_NAME = "EmployeePU";
  public static void main(String[] args) {
      try      {
          Main main = new Main();
          main.initEntityManager();
          main.create();
          System.out.println("Employee successfully added");
          main.closeEntityManager();
      }
      catch(Exception ex)      {
          System.out.println("Error in adding employee");
          ex.printStackTrace();
      }
  }
 private void initEntityManager()  {
 emf = Persistence.createEntityManagerFactory(PERSISTENCE_UNIT_NAME);
         em = emf.createEntityManager();
  }
  private void closeEntityManager()   {
      em.close();    emf.close(); }
 private void create() {
      em.getTransaction().begin();
      Employee employee=new Employee(100);
      employee.setEmpFirstname("bob");
      employee.setEmpLastname("smith");
      em.persist(employee);
      em.getTransaction().commit();
    }
}

El PERSISTENCE_UNIT_NAME representa el nombre de la unidad de persistencia que se utiliza para crear la EntityManagerFactory. La EntityManagerFactory también se puede propagar a través de los componentes de aplicación que utiliza la anotación javax.persistence.PersistenceUnit

En el método create() , un nuevo registro de empleado se inserta en la tabla de empleados. Los datos representados por la instancia de la entidad se conserva en la base de datos una vez que la EntityTransaction asociados con persist() se ha completado. JPA también define las consultas estáticas y dinámicas para recuperar los datos de la base de datos. Consultas estáticas son escritos utilizando la anotación javax.persistence.NamedQuery como se muestra en la clase de entidad Employee. Las consultas dinámicas se definen directamente en la aplicación mediante el método createQuery() de la EntityManager

JPA utiliza una combinación de anotación y XML de configuración. El archivo XML utilizado para este propósito es persistence.xml, que se encuentra en el directorio META-INF de la aplicación. Este archivo define todas las unidades de persistencia que son utilizados por esta aplicación. Cada unidad de persistencia define todas las clases de entidad que se asignan a una sola base de datos. El archivo persistence.xml para la aplicación del empleado es el siguiente:

<persistence>
 <persistence-unit name="EmployeePU" transaction-type="RESOURCE_LOCAL">    <provider>oracle.toplink.essentials.PersistenceProvider</provider>
    <class>com.trial.Employee</class>
    <properties>
      <property name="toplink.jdbc.url" value="jdbc:mysql://localhost:3306/projects"/>
      <property name="toplink.jdbc.user" value="root"/>
      <property name="toplink.jdbc.driver" value="com.mysql.jdbc.Driver"/>
      <property name="toplink.jdbc.password" value="infosys"/>
    </properties>
  </persistence-unit>
</persistence>

El archivo persistence.xml define una unidad de persistencia nombre EmployeePU. La configuración de la base de datos correspondiente está incluida en la unidad de persistencia. Una aplicación puede tener múltiples unidades de persistencia que se refieren a diferentes bases de datos.

En resumen, la JPA ofrece un estándar basado en POJO solución ORM, tanto para Java y Java EE. Utiliza las clases de entidad, los administradores de la entidad, y las unidades de mapa y la persistencia para persistir los objetos de dominio y las tablas de la base de datos.

Cuándo utilizar la JPA

JPA se debe utilizar cuando se necesita una solución para la persistencia basada en un estándar de Java . JPA soporta herencia y polimorfismo, principales características de la programación orientada a objetos. El lado negativo de la JPA es que requiere un proveedor que lo implemente. Estos proveedores de herramientas específicas también ofrecen otras características que no se definen como parte de la especificación de la JPA. Una de esas características es el soporte para el almacenamiento en caché, que no está claramente definida en la JPA, pero está bien soportado por Hibernate, uno de los marcos más populares que implementan la JPA. Asimismo, la JPA esta definida para trabajar con bases de datos relacionales solamente. Si su solución de persistencia debe ampliarse a otros tipos de bases de datos, como bases de datos XML, entonces, la JPA no es la respuesta a su problema de persistencia.