Clases Persistentes
Clases presistentes son clases en una aplicación que implementan las
entidades del problema de negocio (por ejemplo, Customer y Order en una
aplicación de comercio electrónico). No todas las instancias de una
clase persistente se considera que estén en el estado persistente,
una instancia puede en cambio ser transitoria o estar separada.
Hibernate funciona mejor si las clases siguen algunas simples reglas, también
conocidas como el modelo de programación de Viejas Clases Java Planas
(Plain Old Java Object o POJO). Sin embargo, ninguna de estas reglas son
requerimientos rígidos. En cambio, Hibernate3 asume muy poco acerca de
la naturaleza de tus objetos persistentes. Puedes expresar un modelo de dominio en
otras formas: usando árboles de instancias de Map,
por ejemplo.
Un ejemplo simple de POJO
La mayoría de aplicaciones Java requieren una clase
representando felinos.
Aquí hay cuatro reglas principales a seguir:
Implementa un constructor sin argumentos
Cat tiene un contructor sin argumentos. Todas las clases persistentes
deben tener un constructor por defecto (que puede no ser público) de modo que Hibernate
pueda instanciarlas usando Constructor.newInstance(). Recomendamos fuertemente tener
un constructor por defecto con al menos visibilidad de package para la
generación de proxies en tiempo de ejecución en Hibernate.
Provee una propiedad identificadora (opcional)
Cat tiene una propiedad llamada id. Esta
propiedad mapea a la columna clave primaria de la tabla de base de datos. La propiedad
podría llamarse cualquierCosa, y su tipo podría haber sido cualquier tipo
primitivo, cualquier tipo de "envoltura" primitivo, java.lang.String
o java.util.Date. (Si tu tabla de base de datos heredada tiene claves
compuestas, puedes incluso usar una clase definida por el usuario con propiedades de
estos tipos, ver la sección sobre identificadores compuestos luego.)
La propiedad identificadora es estrictamente opcional. Puedes olvidarla y dejar que Hibernate
siga internamente la pista de los identificadores del objeto. Sin embargo, no recomendamos esto.
De hecho, alguna funcionalidad está disponible sólo para clases que
declaran una propiedad identificadora:
Reasociación transitiva de objetos separados (actualizaciones o
fusiones en cascada) - ver
Session.saveOrUpdate()
Session.merge()
Recomendamos que declares propiedades identificadoras nombradas-consistentemente
en clases persistentes. Mas aún, recomendamos que uses un tipo nulable
(es decir, no primitivo).
Prefiere las clases no finales (opcional)
Un aspecto central de Hibernate, proxies, depende de que
las clases persistentes sean ya no finales, o sean ya la implementación
de una interface que declare todos los métodos públicos.
Puedes persistir con Hibernate clases final que no implementen una
interface, pero no serás capaz de usar proxies para recuperación perezosa
de asociaciones, lo que limitará tus opciones para afinar el rendimiento.
Debes también evitar declarar métodos public final
en clases non-final. Si quieres usar una clase con un método public
final, debes deshabilitar explícitamente el uso de proxies estableciendo
lazy="false".
Declara métodos de acceso y modificación para los campos persistentes (opcional)
Cat declara métodos de acceso para todos sus campos persistente.
Muchas otras herramientas ORM persisten directamente variables de instancia. Creemos que
es mejor proveer una indirección entre el esquema relacional y las estructuras internas de la clase.
Por defecto, Hibernate persiste propiedades del estilo JavaBeans, y reconoce nombres de método
de la forma getFoo, isFoo y setFoo.
Puedes cambiar a acceso directo a campos para propiedades en particular, de ser necesario.
Las propiedades no necesitan ser declaradas públicas. Hibernate puede
persistir una propiedad con un par get / set protected o private.
Implementando herencia
Una subclase puede a su vez observar la primera y segunda regla. Hereda su
propiedad identificadora de la superclase, Cat.
Implementando equals() y hashCode()
Tienes que sobrescribir los métodos equals() y hashCode()
si :
piensas poner instancias de clases persistentes en un Set
(la forma recomendada de representar asociaciones multivaluadas)
y
piensas usar reasociación de instancias separadas.
Hibernate garantiza la equivalencia de identidad persistente (fila de base de datos) y
identidad Java sólo dentro del ámbito de una sesión en particular.
De modo que en el momento que mezclamos instancias recuperadas en sesiones diferentes,
debemos implementar equals() y hashCode() si
deseamos tener una semántica significativa de Sets.
La forma más obvia es implementar equals()/hashCode()
comparando el valor identificador de ambos objetos. Si el valor es el mismo, ambos deben ser
la misma fila de base de datos, por lo tanto son iguales (si ambos son agregados a un
Set, sólo tendremos un elemento en el Set).
Desafortunadamente, no podemos usar este enfoque con identificadores generados! Hibernate sólo
asignará valores identificadores a objetos que son persistentes, una instancia recién
creada no tendrá ningún valor identificador! Además, si una instancia no está
salvada y está actualmente en un Set, salvarla asignará un
valor identificador al objeto. Si equals() and hashCode()
están basados en el valor identificador, el código hash podría cambiar,
rompiendo el contrato de Set. Ver el sitio web de Hibernate para una
discusión completa de este problema. Observa que esto no es una incidencia de Hibernate,
sino la semántica normal de Java de identidad de objeto e igualdad.
Recomendamos implementar equals() y hashCode()
usando igualdad de clave de negocio (Business key equality).
Igualdad de clave de negocio significa que el método equals()
compara sólo las propiedades que forman la clave de negocio, una clave que podría
identificar nuestra instancia en el mundo real (una clave candidata
natural):
Nota que una clave de negocio no tiene que ser tan sólida como
una clave primaria candidata de base de datos (ver
). Las propiedades inmutables o
únicas son usualmente buenas candidatas para una clave de negocio.
Modelos dinámicos
Ten en cuenta que las siguientes funcionalidades están
consideradas actualmente experimentales y pueden cambiar en el futuro
cercano.
Las entidades persistentes no necesariamente tienen que estar representadas
como clases POJO o como objetos JavaBean en tiempo de ejecución. Hibernate
soporta además modelos dinámicos (usando Maps de
Maps en tiempo de ejecución) y la representación
de entidades como árboles de DOM4J. Con este enfoque no escribes clases
persistentes, sólo ficheros de mapeo.
Por defecto, Hibernate funciona en modo POJO normal. Puedes establecer una
representación de entidad por defecto para una SessionFactory
en particular usando la opción de configuración
default_entity_mode
(ver ).
Los siguientes ejemplos demuestran la representación usando
Maps. Primero, en el fichero de mapeo,
tiene que declararse un entity-name en vez de
(o como agregado a) un nombre de clase:
]]>
Ten en cuenta que aunque las asociaciones se declaran usando nombres
de clase objetivo, el tipo objetivo de una asociación puede
ser además una entidad dinámica en vez de un POJO.
Después de establecer el modo de entidad por defecto a
dynamic-map para la SessionFactory,
podemos trabajar en tiempo de ejecución con Maps
de Maps:
Las ventajas de un mapeo dinámico es rápido tiempo de ciclo
de prototipado sin la necesidad de implementación de clases de entidad.
Sin embargo, pierdes chequeo de tipos en tiempo de compilación y
muy probablemente tratarás con muchas excepciones en tiempo de ejecución.
Gracias al mapeo de Hibernate, el esquema de base de datos puede estar facilmente
sano y normalizado, permitiendo agregar una implementación apropiada del
modelo de dominio más tarde.
Los modos de representación de entidad pueden ser establecidos
por Session:
Por favor, ten en cuenta que la llamada a getSession()
usando un EntityMode está en la API de
Session, no en la de SessionFactory.
De esta forma, la nueva Session comparte la conexión
JDBC, transacción y otra información de contexto. Esto significa
que no tienes que llamar a flush() ni a close()
en la Session secundaria, y tembién dejar el manejo
de la transacción y de la conexión a la unidad de trabajo primaria.
Puede encontrarse más información sobre las capacidades de
representación XML en .
PORHACER: Documentar el framework de extensiones del usuario en los paquetes
de propiedad y proxies.