Interfaz de Persistencia Java (JPA) - Entidades y Managers

Java Persistence API (JPA) proporciona un modelo de persistencia basado en POJO's para mapear bases de datos relacionales en Java. La persistencia de Java fue desarrollada por expertos de EJB 3.0 como parte de JSR 220, aunque su uso no se limita a los componentes software EJB. Se puede utilizar en aplicaciones web y aplicaciones clientes.

Para ello, combina ideas y conceptos de los principales frameworks de persistencia, como Hibernate, Toplink y JDO. El mapeo objeto-relacional (es decir, la relación entre entidades Java y tablas de la base de datos, queries con nombre, etc) se realiza mediante anotaciones en las propias clases de entidad.

Pero para entender JPA, tendremos que tener claro el concepto "persistencia"
La persistencia o el almacenamiento permanente, es una de las necesidades básicas de cualquier sistema de información de cualquier tipo. En primer lugar, se propuso que el programa tratara los datos haciendo consultas directas a la base de datos. Después, se propuso trabajar con objetos, pero las bases de datos tradicionales no admiten esta opción.
Debido a esta situación, aparecieron los motores de persistencia, cuya función es traducir entre los dos formatos de datos: de registros a objetos y de objetos a registros. Persistir objetos Java en una base de datos relacional implica serializar un árbol de objetos Java en una base de datos de estructura tabular y viceversa. Esencial es la necesidad de mapear objetos Java para optimizar velocidad y eficiencia de la base de datos

Unidades de persistencia

La unidad de persistencia define un conjunto de todas las entidades (clases) que son gestionadas por la instancia del EntityManager en una aplicación. Este conjunto de clases de entidad representa los datos contenidos en una única BBDD.
Las unidades de persistencia se definen en el fichero de configuración persistence.xml. Aquí les mostramos un ejemplo:

<persistence> <persistence-unit name="OrderManagement"> <description>...</description> <jta-data-source>jdbc/MyOrderDB</jta-data-source> <jar-file>MyOrderApp.jar</jar-file> <class>com.widgets.Order</class> <class>com.widgets.Customer</class> </persistence-unit> </persistence>
Este archivo define una unidad de persistencia llamada OrderManagement
Jar-file especifica los ficheros JAR en los que se encuentran las clases persistentes
jta-data-source especifica el nombre global JNDI de la fuente de datos que utiliza el contenedor.

La persistencia puede tener 4 estados diferentes:
Transient: Un objeto recién creado que no ha sido enlazado con el gestor de persistencia.
Persistent: Un objeto enlazado con la sesión (Todos los cambios serán persistentes).
Detached: Un objeto persistente que sigue en memoria después de que termina la sesión: existe en java y en la BDD.
Removed: Un objeto marcado para ser eliminado de la BBDD: existe en java y se borrará de la BDD al terminar la sesión.

JPA - Entity Manager

Antes que nada tenemos que tener bien en claro dos temas muy importanes que son:

Application-managed entity manager
Container-managed entity manager
Para las situaciones en donde no requerimos los servicios ofrecidos por un EJB3 Container, pero querremos utilizar el modelo de persistencia de JPA, el API JPA provee el Application-managed entity manager. En estos casos las aplicaciones son denominadas aplicaciones standalone. Estas aplicaciones que corren fuera de un EJB3 container (porque no lo necesitan) usaran el resource-local transaction provisto por el entity manager, lo que permite que la aplicacion será la encargada de manejar el ciclo de vida del entity manager. Para las situaciones en donde si se requiera de los servicios de un EJB3 container (como por ejemplo JBoss ó WebLogic application server), el API JPA provee el Container-managed entity manager.

Siempre que una transacción sea iniciada, un nuevo contexto de persistencia (persistence context) es creado. Esto es así tanto para el Application-managed entity manager como también para el Container-managed entity manager: Para el caso del Application-managed entity manager (cuando no usamos un application server), la aplicación es la encargada de abrir y cerrar la transacción.
Para el caso del Container managed entity manager (cuando utilizamos un ejb container), por defecto, la transacción es iniciada cuando se invoque desde el cliente al EJB (a un stateless session bean, ahora bien, para los stateful session bean el comportamiento de las transacciones es distinto). La transacción termina cuando finaliza la ejecucion del metodo del session bean.

Interfaces JPA

Los 4 tipos de interfaces de las que se compone JPA son:

javax.persistence.Persistence: Contiene métodos estáticos de ayuda para obtener una instancia de Entity Manager Factory de una forma independiente al vendedor de la implementación de JPA. Una clase de inicialización que va proporcionar un método estático para la creación de una Entity Manager Factory.
javax.persistence.EntityManagerFactory: La clase javax.persistence.Entity.Manager.Factory nos ayuda a crear objetos de EntityManager utilizando el patrón de diseño del Factory. Este objeto en tiempo de ejecución representa una unidad de persistencia particular. Generalmente va a ser manejado como un singleton y proporciona métodos para la creación de instancias EntityManager.
javax.persistence.EntityManagerFactory: La clase javax.persistence.Entity es una anotación Java que se coloca a nivel de clases Java serializables y que cada objeto de una de estas clases anotadas representa un registro de una base de datos.
javax.persistence.EntityManager: Es la interfaz principal de JPA utilizada para la persistencia de las aplicaciones. Cada Entity Manager puede realizar operaciones CRUD (Create, Read, Update, Delete) sobre un conjunto de objetos persistentes. Es un objeto único, no compartido que representa una unidad de trabajo particular para el acceso a datos. Proporciona métodos para gestionar el ciclo de vida de las instancias entidad y para crear instancias Query.
javax.persistence.Query: La interface javax.persistence.Query está implementada por cada vendedor de JPA para encontrar objetos persistentes manejando cierto criterio de búsqueda. JPA estandariza el soporte para consultas utilizando Java Persistence Query Language (JPQL) y Structured Query Language (SQL). Podemos obtener una instancia de Query desde una instancia de un Entity Manager.
javax.persistence.EntityTransaction: Cada instancia de Entity Manager tiene una relación de uno a uno con una instancia de javax.persistence.EntityTransaction, permite operaciones sobre datos persistentes de manera que agrupados formen una unidad de trabajo transaccional, en el que todo el grupo sincroniza su estado de persistencia en la base de datos o todos fallan en el intento, en caso de fallo, la base de datos quedará con su estado original. Maneja el concepto de todos o ninguno para mantener la integridad de los datos.

Entidades

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.
El estado persistente de una entidad puede ser accesible a través de variables de instancia a la entidad o bien a través de las propiedades de estilo de JavaBean.

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.
Una entidad pasara a ser manejada por el contexto de persistencia de JPA cuando ésta sea persistida (mediante el metodo persist() del Entity Manager). En este punto, la entidad pasara a estar asociada a lo que comunmente llamamos el contexto de persistencia. En este caso, y mientras la entidad sea manejada/asociada por el contexto de persistencia (tambien se las conoce como entidades atachadas o attached entities), el estado (valores de la propiedades) de la entidad sera automaticamente sincronizado con la BD.

  • Campos de persistencia permanente: Si la entidad utiliza campos persistencia permanente, 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 de persistencia permanente: Si la entidad utiliza propiedades de persistencia permanente, 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.

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.

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. Las relaciones uno a uno utilizan anotaciones de la persistencia de java "OneToOne".
Uno a muchos: Una entidad, puede estar relacionada con varias instancias de otras entidades. Las relaciones uno a muchos utilizan anotaciones de la persistencia de java "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. Las relaciones muchos a uno utilizan anotaciones de la persistencia de java "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.Este tipo de relación utiliza anotaciones de la persistencia de java "ManyToMany" en los campos o propiedades persistentes.