UNIDAD 5: Gestión de objetos persistentes
eugeniaperez.es
eugeniaperez.es
5.1 Solicitud de objetos con criterios
Hibernate utiliza 3 maneras para recuperar la información:
eugeniaperez.es
5.1 Solicitud de objetos con criterios
A través de Criteria
API de consultas de Hibernate por criterios
Muy extensible, permite realizar consultas sin necesidad de escribir código SQL
Ventajas:
El código limpio
Se aprovecha el IDE (intellisense...)
código SQL compatible con el SGBD especificado...
eugeniaperez.es
5.1 Solicitud de objetos con criterios
A través de Criteria
Desventajas:
La curva de aprendizaje es mayor que la de HQL
Los programadores suelen estar familiarizados con SQL...
eugeniaperez.es
5.1 Solicitud de objetos con criterios
A través de Criteria
La interface org.hibernate.Criteria representa una consulta contra una clase persistente.
La Session es una fábrica de instancias de Criteria.
Criteria crit = session.createCriteria(Cat.class);
crit.setMaxResults(50);
List cats = crit.list();
eugeniaperez.es
5.1 Solicitud de objetos con criterios
A través de Criteria
Un criterio individual de consulta es una instancia de la interface org.hibernate.criterion.Criterion.
La clase org.hibernate.criterion.Restrictions define métodos para establecer criterios.
List cats = session.createCriteria(Cat.class)
.add( Restrictions.like("name", "Fritz%") )
.add( Restrictions.between("weight", minWeight, maxWeight) )
.list();
eugeniaperez.es
5.1 Solicitud de objetos con criterios
A través de Criteria
Las restricciones pueden agruparse y anidarse:
List cats = sess.createCriteria(Cat.class)
.add( Restrictions.like("name", "Fritz%") )
.add( Restrictions.or(
Restrictions.eq( "age", new Integer(0) ),
Restrictions.isNull("age")
) )
.list();
eugeniaperez.es
5.1 Solicitud de objetos con criterios
A través de Criteria
Las restricciones pueden agruparse y anidarse:
List cats = sess.createCriteria(Cat.class)
.add( Restrictions.in( "name", new String[] { "Fritz", "Izi", "Pk" } ) )
.add( Restrictions.disjunction()
.add( Restrictions.isNull("age") )
.add( Restrictions.eq("age", new Integer(0) ) )
.add( Restrictions.eq("age", new Integer(1) ) )
.add( Restrictions.eq("age", new Integer(2) ) )
) )
.list();
Consulta la lista completa de restricciones:
https://docs.jboss.org/hibernate/orm/4.3/javadocs/
eugeniaperez.es
5.1 Solicitud de objetos con criterios
A través de Criteria
También se pueden construir criterios a partir de una instancia de la clase Property mediante un atributo. Por ejemplo:
Property age = Property.forName("age");
List cats = sess.createCriteria(Cat.class)
.add( Restrictions.disjunction()
.add( age.isNull() )
.add( age.eq( new Integer(0) ) )
.add( age.eq( new Integer(1) ) )
.add( age.eq( new Integer(2) ) )
) )
.add( Property.forName("name").in( new String[] { "Fritz", "Izi", "Pk" } ) )
.list();
eugeniaperez.es
5.1 Solicitud de objetos con criterios
Ordenando resultados
También se pueden construir criterios a partir de una instancia de la clase Property mediante un atributo.
Por ejemplo:
List cats = sess.createCriteria(Cat.class)
.add( Restrictions.like("name", "F%")
.addOrder( Order.asc("name") )
.addOrder( Order.desc("age") )
.setMaxResults(50)
.list();
List cats = sess.createCriteria(Cat.class)
.add( Property.forName("name").like("F%") )
.addOrder( Property.forName("name").asc() )
.addOrder( Property.forName("age").desc() )
.setMaxResults(50)
.list();
eugeniaperez.es
5.1 Solicitud de objetos con criterios
Asociaciones
Asociaciones de varias tablas...
usersList = getSession()
.createCriteria(Usuario.class)
.createAlias("compras", "c")
.createAlias("c.productos", "p")
.createAlias("direccion", "d")
.add(Restrictions
.eq("p.estatus", Producto.Estatus.INACTIVO))
.add(Restrictions.eq("d.codigoPostal", postcode))
.list();
eugeniaperez.es
5.1 Solicitud de objetos con criterios
Consultas por ejemplo
La clase org.hibernate.criterion.Example te permite construir un criterio de consulta a partir de una instancia dada.
Cat cat = new Cat();
cat.setSex('F');
cat.setColor(Color.BLACK);
List results = session.createCriteria(Cat.class)
.add( Example.create(cat) )
.list();
eugeniaperez.es
5.1 Solicitud de objetos con criterios
Consultas por ejemplo
Las propiedades a null se pueden configurar:
Example example = Example.create(cat)
.excludeZeroes() //exclude zero valued properties
.excludeProperty("color") //exclude the property named "color"
.ignoreCase() //perform case insensitive string comparisons
.enableLike(); //use like for string comparisons
List results = session.createCriteria(Cat.class)
.add(example)
.list();
eugeniaperez.es
5.1 Solicitud de objetos con criterios
Proyecciones
Se utiliza clase org.hibernate.criterion.
Puedes aplicar una proyección a una consulta llamando al método setProjection().
List results = session.createCriteria(Cat.class)
.setProjection( Projections.rowCount() )
.add( Restrictions.eq("color", Color.BLACK) )
.list();
List results = session.createCriteria(Cat.class)
.setProjection( Projections.projectionList()
.add( Projections.rowCount() )
.add( Projections.avg("weight") )
.add( Projections.max("weight") )
.add( Projections.groupProperty("color") )
)
.list();
eugeniaperez.es
Descarga el código en Bitbucket
Descarga el proyecto hqlCriteria del repositorio de Bitbucket:
Usuario:
Psswd:
URL: https://eugenia_perez@bitbucket.org/eugenia_perez/hqlCriteria.git
eugeniaperez.es
5.2 Solicitud de objetos con HQL
Hibernate Query Language o HQL es muy parecido al SQL estándar, con la diferencia de que es completamente OO (usamos nombres de clases y sus atributos en lugar de nombres de tablas y columnas), por lo que podemos usar cosas como herencia, polimorfismo y asociaciones.
Escribimos las consultas en HQL e Hibernate las convierte al SQL usado por nuestra BD.
eugeniaperez.es
5.2 Solicitud de objetos con HQL
HQL es case-insensitive, pero en los nombres de las clases que estamos recuperando y con sus propiedades SÍ se distinguen.
eugeniaperez.es
5.2 Solicitud de objetos con HQL
Solo necesitaremos las clases del modelo anotadas y el fichero de configuración de Hbm.
A continuación creamos la BD en MySQL con datos de prueba.
Editamos la configuración de Hibernate con nuestro proyecto
Ya podré hacer consultas HQL a BD...
eugeniaperez.es
Descarga el código en Bitbucket
Descarga el proyecto hqlejemplo1 del repositorio de Bitbucket:
Usuario:
Psswd:
URL: https://eugenia_perez@bitbucket.org/eugenia_perez/hqlejemplo1.git
eugeniaperez.es
5.2 Solicitud de objetos con HQL
La cláusula FROM
La cláusula más simple que existe en Hibernate es “FROM”.
from Usuario
from Usuario as u, Permiso
eugeniaperez.es
5.2 Solicitud de objetos con HQL
Asociaciones y Joins
Podemos asignar alias a las entidades asociadas.
O proporcionar condiciones extra:
FROM Usuario u inner join u.permisos as p WITH p.estatus = 1
eugeniaperez.es
5.2 Solicitud de objetos con HQL
Sintaxis de Joins
Como anteriormente, es decir, de forma explícita. Es la forma más clara y recomendable.
Pero también implícita (1:1 o N:1) :
from Usuario u WHERE u.direccion.codigoPostal Like '%12%'
eugeniaperez.es
5.2 Solicitud de objetos con HQL
La cláusula SELECT
eugeniaperez.es
5.2 Solicitud de objetos con HQL
Funciones de agregación
AVG(…), SUM(…), MIN(…), MAX(…)
COUNT(*)
COUNT(…), COUNT(DISTINCT …), COUNT(ALL …)
eugeniaperez.es
5.2 Solicitud de objetos con HQL
Funciones de agregación
eugeniaperez.es
5.2 Solicitud de objetos con HQL
La cláusula WHERE
FROM Usuario u WHERE u.username = 'usr456'
SELECT p.nombre FROM Permiso p WHERE p.id>2 AND p.id<5
FROM Usuario u WHERE u.direccion.codigoPostal = '123456'
eugeniaperez.es
5.2 Solicitud de objetos con HQL
Expresiones
• matemáticas: “+”, “-“, “*”, “/”
• comparación binaria: “=”, “>=”, “<=”, “<>”, “!=”, “LIKE”
• lógicos: “AND”, “OR”, “NOT”, “IN”, “NOT IN”, “BETWEEN”, “IS NULL”,
“IS NOT NULL”, “IS EMPTY”, “IS NOT EMPTY”, “MEMBER OF”, y “NOT MEMBER OF”
• case simple: “CASE… WHEN… THEN… ELSE… END”
• case searched: “CASE WHEN… THEN… ELSE… END”
• concatenación de cadenas: “… || …” o “CONCAT(…,…)”
• “CURRENT_DATE()”,”CURRENT_TIME()”, y “CURRENT_TIMESTAMP()”
• “SECOND(…)”, “MINUTE(…)”, “HOUR(…)”, “DAY(…)” , “MONTH(…)”, y “YEAR(…)”
• “SUBSTRING()”, “TRIM()”, “LOWER()”, “UPPER()”, “LENGTH()”, “LOCATE()”,
“ABS()”, “SQRT()”, “BIT_LENGTH()”, “MOD()”
• “COALESCE()” y “NULLIF()”
• “STR()”
eugeniaperez.es
5.2 Solicitud de objetos con HQL
La cláusula Order By
SELECT p.nombre FROM Permiso p ORDER BY p.nombre
SELECT p.nombre FROM Permiso p ORDER BY p.nombre DESC
ORDER BY atributo1, atributo2, atributo3, … atributo n
eugeniaperez.es
5.2 Solicitud de objetos con HQL
La cláusula Group By
SELECT p.estatus, COUNT(p.estatus) FROM Permiso p GROUP BY p.estatus
eugeniaperez.es
5.2 Solicitud de objetos con HQL
Subconsultas
SELECT DISTINCT(u) FROM Usuario u inner join u.permisos as p
WHERE p in (SELECT p FROM Permiso p WHERE p.estatus = 1)
eugeniaperez.es
5.2 Solicitud de objetos con HQL
Parámetros en HQL
El método “createQuery” recibe como parámetro una cadena que es nuestra consulta HQL.
Hibernate proporciona dos formas de pasar parámetros a nuestras consultas:
eugeniaperez.es
5.2 Solicitud de objetos con HQL
Parámetros en HQL
eugeniaperez.es
5.2 Solicitud de objetos con HQL
Parámetros con nombre
public Usuario getUser(String username, String password)
throws HibernateException {
Usuario user = null;
try {
startTransaction();
Query query = getSession()
.createQuery(
"FROM Usuario u WHERE u. username = :nombreUsuario
AND u. password = :password");
query.setParameter("nombreUsuario", username);
query.setParameter("password", password);
user = (Usuario) query.uniqueResult();
} catch (HibernateException he) {
handleException(he);
} finally {
endTransaction();
}
eugeniaperez.es
Descarga el código en Bitbucket
Descarga el proyecto hqlparameters del repositorio de Bitbucket:
Usuario:
Psswd:
URL: https://eugenia_perez@bitbucket.org/eugenia_perez/hqlparameters.git
5.2 Solicitud de objetos con HQL
Parámetros posicionales estilo JDBC
private static void searchUser() {
Usuario user = null;
UserDAO userDAO = new UserDAO();
try {
user = userDAO.getUser("caperucita", "loboFeroz");
} catch (HibernateException e) {
System.err
.println("An error ocurred while trying to retrieve the user");
e.printStackTrace();
}
if (user == null) {
System.out.println("User not found");
} else {
System.out.println("User found successfully: " +
user.getNombre());
}
}
eugeniaperez.es
5.3 Usando SQL Nativo
eugeniaperez.es
5.3 Usando SQL Nativo
Consultas escalares
sess.createSQLQuery("SELECT * FROM CATS").list();
sess.createSQLQuery("SELECT ID, NAME, BIRTHDATE FROM CATS").list();
sess.createSQLQuery("SELECT * FROM CATS")
.addScalar("ID", Hibernate.LONG)
.addScalar("NAME", Hibernate.STRING)
.addScalar("BIRTHDATE", Hibernate.DATE)
5.3 Usando SQL Nativo
Consultas escalares
public List<Object[]> getActiveProductsNameAndPrice()
throws HibernateException {
List<Object[]> products = null;
try {
startTransaction();
products = getSession()
.createSQLQuery("SELECT * FROM producto WHERE estatus = 1")
.addScalar("nombre").addScalar("precio").list();
} catch (HibernateException he) {
handleException(he);
} finally {
endTransaction();
}
return products;
}
5.3 Usando SQL Nativo
Consulta de entidades
sess.createSQLQuery("SELECT * FROM CATS").addEntity(Cat.class);
sess.createSQLQuery("SELECT ID, NAME, BIRTHDATE FROM CATS").addEntity(Cat.class);
Cómo obtener los objetos entidades desde una consulta sql nativa por medio de addEntity().
Las consultas devolverán una Lista en donde cada elemento es una entidad Cat.
eugeniaperez.es
5.3 Usando SQL Nativo
Consulta de entidades
@SuppressWarnings("unchecked")
public List<Producto> getActiveProducts() throws HibernateException {
List<Producto> products = null;
try {
startTransaction();
products = getSession()
.createSQLQuery("SELECT * FROM producto WHERE estatus = 1")
.addEntity(Producto.class).list();
} catch (HibernateException he) {
handleException(he);
} finally {
endTransaction();
}
return products;
}
eugeniaperez.es
eugeniaperez.es
Descarga el código en Bitbucket
Descarga el proyecto sqlNative del repositorio de Bitbucket:
Usuario:
Psswd:
URL: https://eugenia_perez@bitbucket.org/eugenia_perez/sqlnative.git
5.4 Eventos e interceptores
eugeniaperez.es
5.4 Eventos e interceptores
Interceptores
eugeniaperez.es
5.4 Eventos e interceptores
Interceptores
eugeniaperez.es
5.4 Eventos e interceptores
Interceptores
eugeniaperez.es
public class MyInterceptor extends EmptyInterceptor {}
5.4 Eventos e interceptores
Interceptores
eugeniaperez.es
public class AuditInterceptor extends EmptyInterceptor {
@Override
public boolean onSave(Object entity, Serializable id, Object[] state,
String[] propertyNames, Type[] types) {
}
@Override
public void onDelete(Object entity, Serializable id, Object[] state,
String[] propertyNames, Type[] types) {
}
}
5.4 Eventos e interceptores
Interceptores
eugeniaperez.es
@Override
public boolean onSave(Object entity, Serializable id, Object[] state,
String[] propertyNames, Type[] types) {
if (entity instanceof User) {
User user = (User) entity;
System.out.println("User has been inserted: " + user.getName()
+ ", \"" + user.getUsername() + "\"");
}
return false;
}
5.4 Eventos e interceptores
Interceptores
eugeniaperez.es
5.4 Eventos e interceptores
Interceptores
eugeniaperez.es
protected void startTransaction(Interceptor interceptor)
{
session = HibernateUtil.getSession(interceptor);
session.getTransaction().begin();
}
...
public static Session getSession(Interceptor interceptor) {
return sessionFactory.withOptions().interceptor(interceptor)
.openSession();
}
....
startTransaction(new AuditInterceptor());
5.4 Eventos e interceptores
Interceptores
eugeniaperez.es
public void delete(T entity) throws HibernateException {
try {
startTransaction(new AuditInterceptor());
getSession().delete(entity);
getSession().flush();
} catch (HibernateException he) {
handleException(he);
} finally {
endTransaction();
}
}
5.4 Eventos e interceptores
Eventos
eugeniaperez.es
5.4 Eventos e interceptores
Eventos
eugeniaperez.es
public class LoadUserListener implements PostLoadEventListener {
public void onPostLoad(PostLoadEvent postLoadEvent) { }
}
5.4 Eventos e interceptores
Eventos
eugeniaperez.es
public class LoadUserListener implements PostLoadEventListener {
public void onPostLoad(PostLoadEvent event) {
Object entity = event.getEntity();
if (entity instanceof User) {
User user = (User) entity;
System.out.println("A user has been loaded: " + user.getUsername()
+ ", id=\"" + event.getId() + "\"");
}
}
}
5.4 Eventos e interceptores
Eventos
eugeniaperez.es
5.4 Eventos e interceptores
Eventos
eugeniaperez.es
public class MyEventsListenerIntegrator implements Integrator {
public void integrate(Configuration configuration,
SessionFactoryImplementor sessionFactory,
SessionFactoryServiceRegistry serviceRegistry) {
EventListenerRegistry eventListenerRegistry = serviceRegistry
.getService(EventListenerRegistry.class);
eventListenerRegistry.appendListeners(EventType.POST_LOAD,
new LoadUserListener());
}
public void integrate(MetadataImplementor metadata,
SessionFactoryImplementor sessionFactory,
SessionFactoryServiceRegistry serviceRegistry) {
// TODO Auto-generated method stub
}
public void disintegrate(SessionFactoryImplementor sessionFactory,
SessionFactoryServiceRegistry serviceRegistry) {
// TODO Auto-generated method stub
}
}
5.4 Eventos e interceptores
Eventos
eugeniaperez.es
5.4 Eventos e interceptores
Filtros
eugeniaperez.es
5.4 Eventos e interceptores
Filtros
eugeniaperez.es
@Entity
@FilterDef(name="stockRecordFilter",
parameters=@ParamDef( name="stockRecordFilterParam", type="date" ) )
@Table(name = "stock")
public class Stock implements java.io.Serializable {
...
@OneToMany(fetch = FetchType.LAZY, mappedBy = "stock")
@Filter(
name = "stockRecordFilter",
condition="date >= :stockRecordFilterParam"
)
public Set<StockDailyRecord> getStockDailyRecords() {
return this.stockDailyRecords;
}
}
5.4 Eventos e interceptores
Filtros
eugeniaperez.es
Filter filter = session.enableFilter("stockRecordFilter");
filter.setParameter("stockRecordFilterParam", new Date());
session.disableFilter("stockRecordFilter");
5.4 Eventos e interceptores
Filtros
eugeniaperez.es
@Entity
@FilterDef(name = "passwordFilter", parameters = @ParamDef(name = "passwordFilterParam", type = "integer"))
@Filter(name = "passwordFilter", condition = "length(password) >= :passwordFilterParam")
public class User implements Serializable { ... }
public List<T> get(Class<T> entityClass) throws HibernateException {
List<T> result = null;
try {
startTransaction();
Filter filter = session.enableFilter("passwordFilter");
filter.setParameter("passwordFilterParam", 8);
result = session.createQuery("FROM " + entityClass.getSimpleName())
.list();
} catch (HibernateException he) {
handleException(he);
} finally {
endTransaction();
}
return result;
}
5.4 Eventos e interceptores
Filtros
eugeniaperez.es
@Entity
@FilterDef(name = "passwordFilter", parameters = @ParamDef(name = "passwordFilterParam", type = "integer"))
@Filter(name = "passwordFilter", condition = "length(password) >= :passwordFilterParam")
public class User implements Serializable { ... }
public List<T> get(Class<T> entityClass) throws HibernateException {
List<T> result = null;
try {
startTransaction();
Filter filter = session.enableFilter("passwordFilter");
filter.setParameter("passwordFilterParam", 8);
result = session.createQuery("FROM " + entityClass.getSimpleName())
.list();
} catch (HibernateException he) {
handleException(he);
} finally {
endTransaction();
}
return result;
}