Java Hibernate
Java Hibernate
PERSISTENCIA DE OBJETOS
Qué es la persistencia
Definición
Las base de datos relacionales son la forma por excelencia de almacenar datos. Son
extremadamente flexibles y robustas para la administración de datos. Los DBMS
(DataBase Management Systems) poseen interfaces basadas en SQL para interactuar
con los datos.
Archivos planos
Los archivos planos son otra forma de persistencia. Si bien es posible guardar casi
cualquier informacion, se hace relativamente difícil poder organizar y consultar de
manera eficiente la información deseada.
Problemática
La problemática que se plantea es que los RDBMS (Relational DBMS) están basados
en el modelo relacional, pero por su lado las aplicaciones orientadas a objetos están
basadas en el paradigma de objetos.
Ambos modelos tienen sus propias características, y como consecuencia se genera la
problemática de tratar datos de una tabla como un objeto y viceversa, es decir llevar
datos de un objeto a una tabla.
Se puede decir que “…una tabla es a una clase, lo que un objeto es a un registro…”.
Por ejemplo, la relación entre un cliente y sus facturas será la siguiente en una base
de datos:
Copiar a Clipboard
Por otro lado, siguiendo el mismo ejemplo, la relación entre un cliente y una cuenta
bancaria será la siguiente en un diagrama de clases:
La definición de las clases quedará establecida por:
Copiar a Clipboard
int id;
String nombre;
List cuentasBancarias;
int id;
Cliente cliente;
float saldo;
El problema de la herencia
El problema de la identidad
Copiar a Clipboard
Copiar a Clipboard
String nombre;
String clave;
Para evitar este tipo de problemática, la recomendación es utilizar una PK que nada
tenga que ver con los datos, posiblemente un campo auto-numérico, y construir un
atributo adicional ID en la clase correspondiente.
Copiar a Clipboard
Copiar a Clipboard
int id;
String nombre;
String clave;
Un objeto podría tener a otro objeto como asociado, por ejemplo un Auto tiene un
Stereo, entonces es posible decir que la clase Auto tiene como atributo un objeto del
tipo Stereo (obviamente, Stereo tiene sus propios atributos).
Las asociaciones tienen dirección, es decir que cada clase que forma parte de la
relación, tiene (o no) una referencia a la otra clase.
En una relación unidireccional, una de las dos clases tiene como referencia a la otra.
Por ejemplo, el Auto tiene como referencia al Stereo, o podría ser al revés también,
el Stereo tiene como referencia al Auto.
Copiar a Clipboard
// Atributos
En una relación bidireccional, ambas clases se tienen como referencia. Por ejemplo,
el Auto tiene como referencia al Stereo y el Stereo tiene como referencia al Auto.
Copiar a Clipboard
Copiar a Clipboard
Es normal contar con relaciones del tipo muchos-a-muchos, por ejemplo un Aula
posee muchos alumnos, pero un Alumno puede tener asignada más de un Aula.
Copiar a Clipboard
El problema de la navegación
La relación entre clases está dada a través de una nueva clase, o colecciones. Por
ejemplo, la clase Universidad tiene Facultades, la Facultad tiene Alumnos, el
Alumno tiene Asignaturas, y así sucesivamente.
El problema está en que al realizar la consulta hay que determinar hasta qué nivel de
información (es decir hasta qué objetos) traer como datos.
Qué es ORM
Definición
Maneja los casos más comunes, que son los que aparecen en mayor cantidad. Los
casos especiales deben ser manejados por el usuario, aunque éstos deberían ser los
mínimos.
Organización
Ventajas
Tecnologías ORM
User-defined DAOs
DAO significa Data Access Object. Es un patrón de diseño utilizado para realizar
operaciones contra una base de datos, pero abstrayendo de la lógica de la misma. La
lógica de acceso a datos queda encapsulada dentro de una DAO con lo cual no es
visible para usuarios que utilizan el DAO.
Tiene como desventaja que se paga el precio de “reinventar la rueda”, debido a que
hay que realizar el 100% de la codificación.
Los EJB Entity Beans forman parte de una propuesta de Sun Microsystems
denominada Enterprise Java Beans. Si bien automatizan ciertos aspectos del acceso a
datos, resultan sumamente complejos para aplicaciones de pequeña y mediana
envergadura.
Necesitan estar desplegados dentro de una EJB Container, y como consecuencia el
container se vuelve una dependencia.
No es de las opciones más utilizadas porque requiere un EJB Container para poder
utilizarlos, lo cual agrega significativo complejidad que en la mayoría de los casos
resulta innecesaria.
Jpa
Sus siglas significan Java Persistence API, es una API de persistencia desarrollada
para la plataforma JAVA EE.
JPA es una especificación, lo que significa que por sí sola no se puede implementar.
Podemos utilizar annotations de JPA en nuestras clases, sin embargo sin una
implementación nada sucederá. Hibernate es una implementación de JPA, cumple
las especificaciones de JPA y además aporta sus propias annotations y
funcionalidades.
Hibernate
ObjectDB
TopLink
CocoBase
EclipseLink
OpenJPA
Kodo
DataNucleus, antes conocido como JPOX
Amber
Hibernate
Uno de los aspectos importantes de Hibernate es que está construido con clases java
básicas, es decir que puedo agregar el framework a un proyecto propio. No se
requiere ningún tipo de container (por ejemplo, un application server).
La necesidad de una DAL (Data Access Layer)
PL (Presentation Layer)
BL (Business Layer o Business Logic)
DAL (Data Access Layer)
Qué es DAL
Qué es POJO
Un POJO es un Plain Old Java Object, aunque también a veces se lo denomina Plain
Ordinary Java Object. Es una clase que se encarga de manejar la persistencia.
Copiar a Clipboard
// Setters y getters
...
...
Provee una separación lógica entre las grandes tareas del sistema
Permite que cada capa se concentre en una única tarea
Aumenta la organización
Aumenta la escalabilidad
Facilita el mantenimiento
CONFIGURACIÓN DE HIBERNATE
Introducción
Para poder utilizar Hibernate resulta necesario agregar archivos .jar al proyecto
Jars necesarios
Archivos binarios
Para comenzar con la utilización de Hibernate, será necesario bajar el framework del
sitio de Hibernate:
http://www.hibernate.org
Una vez obtenido el archivo .zip con el framework, descompactarlo. Los archivos
principales/necesarios para su funcionamiento son los que están dentro de la
carpeta /lib/required/
hibernate.jar
Es el archivo principal de Hibernate. Contiene todas la clases fundamentales que
forman parte de Hibernate. Debe ser agregado a nuestro proyecto en el CLASSPATH
correspondiente. El nombre puede variar según la versión de Hibernate que se está
utilizando, desde las últimas versiones se llama hibernate-core (nro. de
versión).Final.jar, también se encuentra dentro de la carpeta /lib/required.
Hibernate utiliza otros archivos jars para llevar a cabo su correcto funcionamiento.
Estos jars se encuentran también en la carpeta /lib/required/ del archivo zip.
Todos los archivos correspondientes a esta carpeta deberán ser agregados a nuestro
proyecto también en el CLASSPATH correspondiente.
http://developers.sun.com/product/jdbc/drivers
Links
El sitio de Hibernate es el punto de partida para obtener los archivos binarios, y para
profundizar el conocimiento:
http://www.hibernate.org/
Documentación
https://docs.jboss.org/hibernate/orm/4.3/javadocs/
Configuración
Jerarquía de directorios
Directorio /jar
Paquete/directorio entities
Contiene las clases que se utilizan para representar a las tablas, junto con los archivos
de extensión xml que poseen el mapeo entre una clase y una tabla.
Propiedades de Hibernate
Introducción
Existe una alternativa que es usar un archivo xml, formado por tags predefinidos, que
reemplaza al uso de archivos .properties.
hibernate.connection.driver_class
hibernate.connection.driver_class = com.mysql.jdbc.Driver
hibernate.connection.url
hibernate.connection.url = jdbc:mysql://localhost/hibernate
hibernate.connection.username
hibernate.connection.username = usuario
hibernate.connection.password
hibernate.connection.password = 123456
hibernate.dialect
hibernate.dialect = org.hibernate.dialect.MySQLDialect
Existen dialectos definidos para cada uno de los DBMS. Los más conocidos se
detallan en la tabla siguiente
DBMS Dialecto
DB2 org.hibernate.dialect.DB2Dialect
HypersonicSQL org.hibernate.dialect.HSQLDialect
Informix org.hibernate.dialect.InformixDialect
Pointbase org.hibernate.dialect.PointbaseDialect
PostgreSQL .hibernate.dialect.PostgreSQLDialect
Microsoft SQL
org.hibernate.dialect.SQLServerDialect
Server
MySQL org.hibernate.dialect.MySQLDialect
Oracle org.hibernate.dialect.OracleDialect
Progress org.hibernate.dialect.ProgressDialect
SAP DB org.hibernate.dialect.SAPDBDialect
Sybase org.hibernate.dialect.SybaseDialect
Copiar a Clipboard
hibernate.connection.driver_class=com.mysql.jdbc.Driver
hibernate.connection.url=jdbc:mysql://localhost/hibernate
hibernate.connection.username=root
hibernate.connection.password=root
hibernate.dialect=org.hibernate.dialect.MySQLDialect
Para obtener el MySQL Database Server, es posible bajarlo del siguiente link:
http://dev.mysql.com/downloads/mysql/4.1.html
http://dev.mysql.com/downloads/workbench/
Para poder trabajar con Hibernate, se deberá crear el esquema de base de datos y las
tablas correspondientes. A continuación se presenta el código DDL para la creación
de una base de datos:
Copiar a Clipboard
Copiar a Clipboard
CREATE TABLE autos
);
Creación de un POJO
Qué es un POJO
Para realizar este “mapeo” entre clases y tablas, es necesario que las clases sean
POJOs, es decir (Plain Old Java Object). Se denomina POJO a una clase que
contiene las características presentadas a continuación.
Características de un POJO
Para que la clase sea un POJO deberá cumplir con las características:
Ejemplo de un POJO
Copiar a Clipboard
// Constructor vacío
public Auto(){}
marca = unaMarca;
modelo = unModelo;
// Setters y getters
...
...
Hibernate Annotations
Qué son
Copiar a Clipboard
) ENGINE=MyISAM;
Copiar a Clipboard
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name="autos")
// Atributos
@Id
@GeneratedValue(strategy= GenerationType.AUTO)
@Column(name="au_marca")
@Column(name="au_marca")
@Column(name="au_modelo")
public Auto() {
marca = unaMarca;
modelo = unModelo;
return id;
this.id = id;
}
return marca;
this.marca = marca;
return modelo;
this.modelo = modelo;
1) En primer lugar, Hibernate nos permite colocar las annotations sobre nuestras
properties, o sobre los accesors. En el primer caso, accederá a nuestros atributos
directamente y en el segundo a través de los getters y setters.
Supongamos que dos campos de nuestra clase se mapean sobre uno solo de la tabla
correspondiente, el típico caso de Persona, con nombre y apellido. Si usamos
annotations sobre accesors, podríamos lograr que el setter reciba un String, lo parsee
y lo reparta entre los atributos nombre y apellido de mi clase. El getter, por su parte,
concatenaría nombre + apellido y lo devolvería a Hibernate para que lo cargue en la
columna correspondiente. A su vez, basándonos en los getters logramos un mayor
control pudiendo agregar la información que deseemos a la columna correspondiente.
La clase TestAutos
Se utilizará la clase TestAutos para lograr hacer el “hola mundo” con las operaciones
básicas.
Copiar a Clipboard
insertarAuto();
consultarAutos();
modificarAuto();
consultarAutos();
eliminarAuto();
consultarAutos();
La interfaz org.hibernate.Session
Para poder trabajar con la base de datos resulta necesario obtener una sesión, es decir
un objeto que tiene implementado a través de su clase la interfaz Session. Para
conseguir una sesión, es necesario tener configurado Hibernate: database driver, url
connection, user, password.
Copiar a Clipboard
config.setProperties(System.getProperties());
factory = config.buildSessionFactory(builder.build());
Copiar a Clipboard
registerMappers(config);
config.setProperties(getHibernateProperties());
factory = config.buildSessionFactory(builder.build());
return factory.openSession();
props.put("hibernate.connection.driver_class",
"com.mysql.jdbc.Driver");
props.put("hibernate.connection.url",
"jdbc:mysql://localhost/hibernate");
props.put("hibernate.connection.username",
"root");
props.put("hibernate.connection.password", "");
props.put("hibernate.dialect",
"org.hibernate.dialect.MySQLDialect");
return props;
config.addAnnotatedClass(ar.com.educacionit.hibernate.entities.Auto.class);
}
Cómo realizar una Inserción
Copiar a Clipboard
Session session =
EducacionITSessionManager.getSession();
Transaction tx = session.beginTransaction();
session.save(a1);
tx.commit();
session.close();
Copiar a Clipboard
Iterator<Auto> it = getAutos().iterator();
while( it.hasNext() )
Auto a = it.next();
System.out.println(a);
}
Session session =
EducacionITSessionManager.getSession();
List losAutos =
session.createQuery("FROM entities.Auto").list();
session.close();
return losAutos;
Para actualizar un auto correspondiente a la tabla autos, tal que el auto tenga como
id=1, se desarrollara el método modificarAuto(), presentado a continuación:
Copiar a Clipboard
a1.setId(1L);
Session session =
EducacionITSessionManager.getSession();
Transaction tx = session.beginTransaction();
session.update(a1);
tx.commit();
session.close();
Para eliminar un auto correspondiente a la tabla autos, tal que el auto tenga como
id=1, se desarrollara el método eliminarAuto(), presentado a continuación:
Copiar a Clipboard
a1.setId(7L);
Session session =
EducacionITSessionManager.getSession();
Transaction tx = session.beginTransaction();
session.delete(a1);
tx.commit();
session.close();
CLASE 2
La clase org.hibernate.cfg.Configuration
La implementación de la interfaz Configuration es utilizada para configurar
Hibernate. Se utiliza una instancia de Configuration para establecer tanto los
mappers como las propiedades de Hibernate.
La interfaz org.hibernate.SessionFactory
Existe un único objeto de este tipo en la aplicación (por defecto), aunque se puede
configurar más de uno en caso de necesitar accesos a más de una base de datos.
La interfaz org.hibernate.Session
Los objetos pertenecientes a la clase que implementa Session son los más utilizados
en una aplicación de Hibernate. Representa una unidad de trabajo y pueden ser
comprendidos como la combinación entre una conexión y una transacción.
La interfaz org.hibernate.Query
Los objetos pertenecientes a la clase que implementa Query se utilizan para realizar
consultas contra la base de datos. Permite construir una consulta y ejecutarla.
Las consultan pueden ser escritas en HQL (Hibernate Query Language) o en SQL
nativo. Se utiliza en conjunto con un objeto del tipo Criteria.
La interfaz org.hibernate.Transaction
El paquete org.hibernate.classic
LOGGING
Qué es
Hibernate tiene la capacidad de mostrar cómo va realizando las operaciones de
ABMC, es decir el código SQL que va ejecutando. Por ejemplo, al utilizar un objeto
Query y ejecutarlo, podemos ver la consulta SQL que está lanzando Hibernate al
DBMS.
Desde la versión 4.0 Hibernate utiliza las librerías de JBoss Logging, al igual que
SLF4J y Jakarta’s commons-logging, JBoss es un “logging bridge” que provee
integración con numerosos frameworks de logging.
JBoss LogManager
Log4j 2
Log4j 1
Slf4j
JDK logging
http://docs.jboss.org/hibernate/orm/4.3/topical/html/logging/Logging.html
Categorías de interés
Category Description
Log all SQL statements as they are executed with
org.hibernate.SQL
through JDBC
Log all values as they are bound to JDBC
org.hibernate.type.descriptor.sql
parameters and extracted from JDBC results
Log all SQL DDL statements as they are executed
org.hibernate.tool.hbm2ddl during execution of any of the schema migration
tools
Log the state of all entities (max 20 entities)
org.hibernate.pretty
associated with the session at flush time
org.hibernate.cache Log all second-level cache activity
org.hibernate.hql.internal.ast.ASTLog HQL and SQL ASTs during query parsing
Log everything. This is a lot of information but it
org.hibernate
is useful for troubleshooting
commons-logging-x.x.x.jar
log4j-x.x.x.jar
“x” corresponde a la versión correspondiente del .jar. Ambos vienen junto con todos
los jars de Hibernate. Se deberá también agregar un archivo de configuración
llamado log4j.properties en el CLASSPATH.
El archivo log4j.properties
Copiar a Clipboard
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=
log4j.rootLogger=warn, stdout
log4j.logger.net.sf.hibernate=debug
log4j.logger.net.sf.hibernate.type=debug
log4j.logger.net.sf.hibernate.ps.PreparedStatementCache=
debug
La propiedad hibernate.show_sql
La propiedad hibernate.show_sql se utiliza para poder visualizar las consultas que va
realizando Hibernate. Para configurarla, se deberá agregar la propiedad
hibernate.show_sql en el archivo de configuración utilizado.
Copiar a Clipboard
props.put("hibernate.connection.driver_class",
"com.mysql.jdbc.Driver");
props.put("hibernate.connection.url",
"jdbc:mysql://localhost/hibernate");
props.put("hibernate.connection.username", "root");
props.put("hibernate.connection.password", "root");
props.put("hibernate.dialect",
"org.hibernate.dialect.MySQLDialect");
props.put("hibernate.show_sql", "true");
ADMINISTRACIÓN DE SESIONES
Qué es un singleton
El Singleton es un patrón de diseño que tiene como objetivo construir una única
instancia de un objeto. Al intentar obtener un nuevo objeto solicitándolo a la clase, la
misma clase entrega al cliente una instancia previamente creada.
Asegura que habrá una única instancia de la clase que tiene aplicado este patrón.
CLASE 3
Qué es
Utiliza en sus consultas clases y atributos, a diferencia de SQL que utiliza tablas y
campos. Si bien no es un lenguaje case-sentitive, las clases y los atributos son case-
sentitive, así que hay que tener cuidado a la hora de armar consultas.
Cláusulas
From
La cláusula from es la cláusula más sencilla, se utiliza para obtener todos los ítems
de una tabla.
Copiar a Clipboard
Iterator<Clase> it = lista.iterator();
while( it.hasNext() ) {
Clase c = it.next();
System.out.println("Campo1: " + c.getAtrib1() );
System.out.println("Campo2: " + c.getAtrib2() );
select
La cláusula select se utiliza para seleccionar qué datos traer de una o más tablas.
Generalmente se utiliza cuando se necesita traer datos de atributos de distintos
objetos.
Esto se debe a que se podrían traer datos de más de una tabla, con lo cual sería
imposible determinar a que objeto pertenece.
En SQL sería:
Copiar a Clipboard
En HQL sería:
Copiar a Clipboard
String strQuery =
"SELECT c1.atrib, c2.atrib FROM paquete.Clase
Iterator it = qry.iterate();
while( it.hasNext() ) {
Object[] row = (Object[]) it.next();
System.out.println("Atrib_c1: " + row[0]);
System.out.println("Atrib_c2: " + row[1]);
where
En SQL sería:
Copiar a Clipboard
En HQL sería:
Copiar a Clipboard
String strQuery =
Iterator<Clase> it = qry.iterate();
while( it.hasNext() ) {
Clase unaClase = it.next();
System.out.println("Atrib: " + unaClase.atrib);
}
Copiar a Clipboard
SELECT campo1 FROM tabla1 WHERE campo2 LIKE ‘A%’;
En HQL sería:
Copiar a Clipboard
String strQuery =
Iterator<Clase> it = qry.iterate();
while( it.hasNext() ) {
Clase unaClase = it.next();
System.out.println("Atrib: " + unaClase.atrib);
}
group by
En SQL sería:
Copiar a Clipboard
En HQL sería:
Copiar a Clipboard
String strQuery =
"SELECT sum(c1.atrib1)
Iterator it = qry.iterate();
while( it.hasNext() ) {
Object[] row = (Object[]) it.next();
System.out.println("Suma: " + row[0]);
}
order by
La cláusula order by se utiliza para ordenar información por algún atributo (campo).
En SQL sería:
Copiar a Clipboard
En HQL sería:
Copiar a Clipboard
String strQuery =
Iterator<Clase> it = qry.iterate();
while( it.hasNext() ) {
Clase unaClase = it.next();
System.out.println("Atrib: " + unaClase.atrib);
}
Utilización de funciones
Introducción
Es posible utilizar las funciones propias de SQL. Están disponibles las funciones
típicas de ANSI-SQL:
avg()
sum()
min()
max()
count(*)
También está disponible la palabra clave DISTINCT
Copiar a Clipboard
En HQL sería:
Copiar a Clipboard
String strQuery =
count
sum
avg
max
min
A veces resulta necesario lanzar consultas específicas de SQL. Para esto es necesario
utilizar el SQL nativo, es decir SQL puro y/o SQL propietario del DMBS que se está
utilizando.
A diferencia del uso de HQL que se realizaba con el método createQuery(), para
utilizar SQL nativo es necesario emplear el método createSQLQuery().
El método createSQLQuery()
Copiar a Clipboard
.addEntity(Auto.class)
.list();
Para esto, es necesario construir una consulta con marcas donde se reemplazan los
valores.
Por ejemplo:
Copiar a Clipboard
Copiar a Clipboard
qry.setString("p1", unValor);
Paginación
Definición
La paginación es la posibilidad de trabajar con parte del resultado que satisface una
consulta. Muchas veces resulta imposible mostrar una cantidad importante de
registros, y lo que se hace es mostrarlos agrupados por una cantidad. A esta cantidad
de registros se la denomina “Página”.
El método setMaxResults()
Copiar a Clipboard
"FROM paquete.Clase”);
qry.setMaxResults(tamanoPagina);
List lista = qry.list();
El método setFirstResult()
El método setFirstResult() establece cuál será el primer registro a traer, esto se debe a
que a veces resulta necesario traer del registro 0 al 100, o tal vez del registro 500 al
600.
Copiar a Clipboard
"FROM paquete.Clase”);
qry.setFirstResult(primerRegistroATraer);
Named Queries
Los Named queries en hibernate son una forma de agrupar sentencias HQL en una
única locación para luego referirse a ellos cuando sea necesario. Esto ayuda mucho a
limpiar el código porque las sentencias HQL ya no se encuentran mezcladas entre el
código de nuestras clases.
Copiar a Clipboard
@NamedQueries({
@NamedQuery(
name = "obtenerAutosCaros",
})
El método getNamedQuery()
Copiar a Clipboard
.list();
CLASE 4
Problemática
No es posible modelar la herencia en un modelo de datos, lo cual produce un gap
entre el modelo relacional y el modelo de objetos. SQL no provee soporte para
herencia.
Soluciones
Esta propuesta es la solución más sencilla. Se utiliza una clase concreta por cada
tabla. Por cada atributo de la clase, existe un campo en la tabla correspondiente.
Es la solución ideal si no se tienen en cuenta conceptos como herencia y
polimorfismo. Descarta el uso de relaciones de herencia y polimorfismo del modelo
relacional.
Representa la herencia a través de claves foráneas, ya que por cada subclase existe
una tabla. Cada subclase, incluyendo clases abstractas, tiene su propia tabla. Cada
tabla contiene campos solo por cada atributo que no es heredado.
La clave primaria es a su vez la clave foránea correspondiente a la superclase. Para
obtener los datos de una subclase, es necesario hacer un join entre la tabla que
representa a la superclase y la tabla que representa a la subclase.
Se construye una tabla por cada jerarquía de clases, donde la tabla posee un campo
por cada atributo de la jerarquía de clases. Adicionalmente, se utiliza un campo de
tipo discriminador (discriminator) para establecer qué tipo de clase corresponde a
cada registro.
Integra el concepto de polimorfismo y es la mejor estrategia en términos de
performance y simplicidad.
La única restricción que posee es que los atributos de las subclases deben quedar
como campos que pueden estar en NULO.
Para confeccionar esta relación, dentro del modelo relacional será necesario construir
la siguiente tabla denominada transportes:
Copiar a Clipboard
@Entity
@Table(name = "transportes")
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(
name="tr_discriminador",
discriminatorType=DiscriminatorType.STRING
@DiscriminatorValue(value="T")
@Id
@GeneratedValue
@Column(name = "tr_id")
@Column(name = "tr_largo")
}
-----------------------------------------------------
@Entity
@Table(name="transportes")
@DiscriminatorValue("A")
public class Auto extends Transporte {
@Column(name="tr_au_patente")
private String patente;
// Constructors and Getter/Setter methods,
}
El código presentado en negrita es el código necesario para representar la relación de
herencia dentro de hibernate. El discriminador se utiliza para guardar un valor en la
tabla que identificará si un registro corresponde a un Transporte o a un Auto.
La clase Transporte es la superclase, por tal motivo los valores para las
annotations @Inheritance y @DiscriminatorColumn se definen en la misma.
@Inheritance – Define la estrategia a utilizar, se define en la superclase de la
jerarquía. Los valores posibles son JOINED, SINGLE_TABLE y
TABLE_PER_CLASS.
@DiscriminatorColumn – Es utilizada para definir la columna que será utilizada
como discriminador, se utiliza en las estrategias SINGLE_TABLE and JOINED. La
estrategia de mapeo y la columna del discriminador se especifican solamente en la
superclase de la jerarquía.
Si la annotation para @DiscriminatorColumn no está definida, y una columna para el
discriminador es necesaria, los valores por defecto son "DTYPE" para el nombre
y DiscriminatorType.STRING para el tipo.
@DiscriminatorValue – Es utilizada para especificar el valor de la columna
discriminadora para las entidades de cada tipo. La
annotation DiscriminatorValue puede ser solamente especificada en una clase
concreta.
CLASE 5
ASOCIACIONES
En esta clase de relaciones existe una entidad que tiene como atributo una colección
de entidades de otro tipo. A la entidad que posee la colección se la conoce como
extremo one. La entidad a la que pertenecen los elementos de la colección se la
conoce como extremo many. La entidad del extremo many se relacionará como
máximo con una entidad del extremo one.
Ítem y Factura:
Copiar a Clipboard
Item
Copiar a Clipboard
Para definir cómo se mapearán las clases hay ciertos aspectos del negocio que
primeramente deberíamos tener definidos.
1. En nuestro sistema agregaremos los ítems a la factura, lo que es más común a
la hora de trabajar con objetos complejos, en lugar de a cada ítem setearle la
factura asociada.
2. El ciclo de vida del Ítem depende del de la factura. Si no existe la factura no
tienen sentido sus ítems. Si se elimina una factura, se eliminan también sus
ítems.
3. Acceso a la información: siempre que traigo los datos de una factura traigo
los datos de sus ítems, o accedo a los datos de los ítems en una segunda
instancia. Existen las dos posibilidades, analizaremos las dos situaciones con
las opciones que nos da Hibernate.
Existen otros aspectos que irán surgiendo a medida que avancemos, no obstante por
ahora podemos comenzar a atacar el mapeo de los objetos.
Copiar a Clipboard
@Entity
@Table(name = "items")
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "it_id")
@ManyToOne
@JoinColumn(name = "fac_id")
@Column(name = "it_cantidad")
private Long cantidad;
@Column(name = "it_descripcion")
Observaciones:
Con este simple mapeo sería suficiente para establecer la relación entre ambas
entidades, no obstante nos puede interesar recorrer la relación en forma bidireccional.
Copiar a Clipboard
@Entity
@Table(name = "facturas")
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "fac_id")
@OneToMany
@JoinColumn(name = "fac_id")
Observaciones:
El punto uno se refería a la forma en que se iría armando el objeto compuesto, como
los ítems se agregarían a la factura:
Copiar a Clipboard
f.getItems().add(i);
El objetivo sería lograr que cuando se persista el objeto factura también se persistan
los ítems y queden relacionados mediante la FK.
Por defecto Hibernate asume que los dos extremos de la relación se sincronizan con
la base de datos. Con lo cual, tanto si agrego un ítem a una factura o viceversa, este
cambio se persistirá en la base de datos.
MappedBy
Con esta configuración podemos lograr que las modificaciones que se realicen en la
colección del extremo One no se sincronicen con la BD.
Copiar a Clipboard
@OneToMany(mappedBy="factura")
Copiar a Clipboard
factura.getItems().add(item);
Copiar a Clipboard
Item.setFactura(factura);
Cascading
Este tema se encuentra relacionado con el segundo aspecto a tener en cuenta que
planteamos en el inicio.
Copiar a Clipboard
Factura fac = new Factura();
fac.getItems().add(it);
DB.save(fac);
El ciclo de vida de ambos objetos está relacionado, tanto si agrego como si remuevo
un ítem en el momento de persistir la información en la DB todos los cambios
quedan reflejados.
Copiar a Clipboard
Copiar a Clipboard
@OneToMany(cascade =
CascadeType.ALL,mappedBy="factura", orphanRemoval=true)
Fetching
El tercer punto que abordamos es la forma en que vamos a buscar la información a la
base de datos, la diferencia radica en que si vamos a buscar una factura a la base de
datos traemos siempre la información de los ítems, o esta información la traemos en
una segunda instancia.
Lazy: al traer un ítem, no nos traerá aún la factura asociada. Al traer el ítem se
realizará un SELECT y otro cuando se desee obtener la información de la factura.
Eager: realiza un Join entre la tabla ITEM y FACTURA, para poder cargar ambos
objetos en el momento de obtener el ítem desde la Base de datos.
Copiar a Clipboard
@OneToMany(fetch = FetchType.EAGER/LAZY).
One-To-One
Es una relación simple “uno a uno” donde una tabla tiene una FK a otra.
Ejemplo:
Copiar a Clipboard
@Entity
@Table(name = "CLIENTE")
@OneToOne
@JoinColumn(name = "DIR_ID")
}
@Entity
@Table(name = "DIRECCION")
@OneToOne(mappedBy="direccion")
Many-To-Many
A la hora de mapear esta relación podemos optar por utilizar dos relaciones many-to-
one, de la forma ya vista, en caso de que tenga sentido para nuestro sistema mapear
la tabla intermedia, ya sea porque posee información adicional o por algún otro
motivo.
Si optamos por ignorar la tabla intermedia podremos mapear una relación many-to-
many.
Copiar a Clipboard
@Entity
@Table(name = "CATEGORIA")
@ManyToMany
@JoinTable(name = "CATEGORIA_ITEM",
Bidireccional:
Copiar a Clipboard
@ManyToMany(mappedBy = "items")
CLASE 6
TRANSACCIONES
La interfaz org.hibernate.Transaction
Como se presentó anteriormente, representa el concepto de transacción en forma
transparente para el cliente. Permite trabajar con un conjunto de acciones de forma
atómica, es decir que se realizan todas las acciones o no se realiza ninguna
Tiene ciertas ventajas, como por ejemplo si modificamos más de una vez un mismo
objeto, no se realizan idas y vueltas a la base de datos sino que se resuelve en
memoria.
El método load()
Su utilización es la siguiente:
Copiar a Clipboard
El método get()
Su utilización es la siguiente:
Copiar a Clipboard
El método beginTransaction()
El método flush()
A veces también es invocado antes de una consulta, en caso de que algún valor en
memoria afecte el resultado de la consulta
El método setFlushMode()
El método commit()
El método rollback()
Los cambios realizados previos al commit() no tienen efecto si luego del commit() se
llama al método rollback().
Copiar a Clipboard
// Variables
Transaction tx = null;
try {
session = EducacionITSessionManager.getSession();
// Comienza la transacción
tx = session.beginTransaction();
...
...
tx.commit();
}
catch (Exception e) {
if (tx!=null)
tx.rollback();
finally {
if(session!=null)
session.close();
CLASE 7
HERRAMIENTAS COMPLEMENTARIAS
Introducción
Una vez configurado el acceso a la base de datos desde NetBeans, podemos utilizar
el mismo para generar en forma automática el código de los POJOs con las
anotaciones incluidas a partir de las tablas creadas en la base. Para ellos creamos un
nuevo proyecto y haciendo click derecho en cualquier paquete nos dirigimos a la
opción New -> Entity Classes from Database...
Esto desplegará una pantalla donde podemos seleccionar las tablas a partir de las
cuales queremos generar el código.
Otro tema a tener en cuenta es el nombre de las tablas y los campos, Netbeans
nombrará a las clases y a los atributos con los mismos nombres que poseen las tablas
y las columnas en la base de datos, por tal motivo no se recomienda tener las tablas
con nombres en plural y las columnas con nombres que sean aplicables a los
atributos de las clases.-