Consultas Con HibernateTemplate
En Spring Framework, Los DAO que heredan de HibernateDaoSupport tienen acceso al método getHibernateTemplate, el cual devuelve una clase con diversas utilidades para manejar objetos con Hibernate.
Contenido
Buscar un objeto por ID
Si necesitamos buscar un objeto por su ID, tenemos básicamente dos opciones: usar el método get() o el método load() de la Session de Hibernate.
get() busca una entidad por su PK, y devuelve null si no la encuentra. Por otro lado, load() realiza la misma operación, pero tira una DataAccessException si no se encuentra. En general, debe usarse load() cuando no se espera que la entidad no se encuentre.
public Invasor buscarInvasorPorId(Long id) { return getHibernateTemplate().get(Invasor.class, id); }
Buscar colecciones con Criteria
Existen dos formas básicas de realizar estas consultas: utilizando Criteria, o escribiendo la consulta en HQL.
Generalmente, utilizar Criteria es más simple y facil de programar, y suele ser una buena elección cuando en la consulta se realiza sobre el objeto mapeado (y las relaciones que tenga explicitamente mapeadas). En otros casos, el query en HQL puede ser más conveniente.
Suponiendo que un Invasor tenga un Estado (relación muchos-a-uno desde el Invasor al Estado), se puede referenciar directamente al Estado de un Invasor (como si fuera un atributo más... que de hecho, lo es!).
public Collection<Invasor> buscarInvasoresPorEstado(Long idEstado) { DetachedCriteria criteria = DetachedCriteria.forClass(Invasor.class); criteria.add(Restrictions.eq("estado.id", idEstado)); return getHibernateTemplate().findByCriteria(criteria); }
La clase Restrictions tiene varios operadores útiles, como ser LIKE case-unsensitive. Además, se pueden establecer criterios de ordenamiento.
public Collection<Invasor> buscarInvasoresPorEstadoNombre(Long idEstado, String nombre) {
DetachedCriteria criteria = DetachedCriteria.forClass(Invasor.class); criteria.add(Restrictions.eq("estado.id", idEstado)); criteria.add(Restrictions.ilike("nombre", nombre)); criteria.addOrder(Order.desc("fechaEnrolamiento")); return getHibernateTemplate().findByCriteria(criteria); }
Buscar colecciones con HQL
En ciertas circunstancias, puede ser preferible usar HQL. HibernateTemplate también provee algunos métodos útiles para esto. Supongamos el mismo método buscarInvasoresPorEstado(), esta vez resuelto con HQL.
private final String QUERY = "from Invasor invasor where invasor.estado.id = ?";
public Collection<Invasor> buscarInvasoresPorEstado(Long idEstado) { return getHibernateTemplate().find(QUERY, idEstado); }
Otra alternativa es utilizar el método iterate() que devuelve un iterador para recorrer los resultados.
private final String QUERY = "from Invasor invasor where invasor.estado.id = ?";
public Iterator<Invasor> buscarIteradorDeInvasoresPorEstado(Long idEstado) { HibernateTemplate ht = getHibernateTemplate(); ht.setFetchSize(15); Iterator it = ht.iterate(QUERY, idEstado); return it; }
Importante: Notar que con esta alternativa, se modifica el fetch size del template de hibernate incluso para las siguientes utilizaciones del dao. Para utilizar el default, debería volver a setearse en 0.
Un análisis de estas alternativas se puede ver en Eficiencia Ejecutando Querys Con Hibernate
Buscar colecciones por muestra
A veces puede ser útil realizar una búsqueda por "muestra". En estas búsquedas, se crea un objeto mapeado seteando los valores que queremos ubicar, y este mismo objeto es usado como filtro para crear la consulta. En este tipo de búsquedas no se tiene en cuenta el ID del objeto de muestra (es decir, aunque el objeto de muestra tenga seteado su PK, no será utilizada para la búsqueda).
public Collection<Invasor> buscarInvasoresPorFechaEnrolamiento(Date fechaEnrolamiento) { Invasor invasor = new Invasor(); invasor.setFechaEnrolamiento(fechaEnrolamiento); return getHibernateTemplate().findByExample(invasor); }
Buscar un sólo objeto con consultas
Los métodos find (de Criteria o HQL) siempre devuelve colecciones de objetos. Pero, ¿qué pasa si sabemos que nuestro query sólo puede devolver una instancia? Para esto, podemos usar la clase DataAccessUtils de Spring.
Como todos saben, cada comandante de la flota Irken sólo puede liderar una nave espacial (son petisos los Irken, no les daría para ir paseando por diversas naves...)
public NaveEspacial buscarNaveEspacialPorComandante(Long idInvasor) { DetachedCriteria criteria = DetachedCriteria.forClass(NaveEspecial.class); criteria.add(Restrictions.eq("idInvasorComandate", idInvasor)); return (NaveEspacial) DataAccessUtils.uniqueResult(getHibernateTemplate().findByCriteria(criteria));
//jaime
}
El método DataAccessUtils.uniqueResult() lanzará una excepción si la consulta devuelve más de un resultado.
Paginar resultados
Los métodos de búsqueda tienen una forma simple para paginar resultados. El método findByCriteria(criteria, desde, cantidad) permite obtener un set reducido de datos.
El siguiente método devuelve el "Top ten" de los mejores Invasores de la flota.
public Collection<Invasor> buscarMejoresInvasores() { DetachedCriteria criteria = DetachedCriteria.forClass(Invasor.class); criteria.addOrder(Order.desc("cantPlanetasConquistados")); return getHibernateTemplate().findByCriteria(criteria,0,10); }