Volvemos con la segunda parte de «Conociendo un ORM», continuando el desarrollo que dejamos a medias con Hibernate. Una vez realizada la configuración, los modelos y sus mapeos correspondientes solo nos queda apoyarnos de toda la configuración para poder obtener, insertar, editar y eliminar los datos de la aplicación haciéndolos persistir en la base de datos.
Un buen hábito de desarrollo es construir una clase HibernateUtil que se apoye en el patrón Singleton. El objetivo de emplear este patrón es el de garantizar que una clase solo tenga una instancia en la aplicación, y proporcionar un único punto de acceso global a ella, Hibernate trabaja con sesiones y genera una instancia de la base de datos para trabajar con ella, por lo tanto es lógico y un buen hábito de trabajo cuando se trabaja con éste framework de persistencia crear esta clase que proporciona un único punto de acceso a dicha instancia, evitando crear una sesión distinta desde distintos puntos de la aplicación que finalmente nos puede llevar a generación de errores y consumo innecesario de memoria.
Para ello se desarrolla la clase “HibernateUtil” en la cual declaramos un atributo “static” del tipo “SessionFactory” asegurándonos de que solo existe una instancia. Además este atributo se define como final para que no pueda ser modificado ni alterado por ningún cliente que lo referencie. Gracias al patrón Singleton obtenemos un acceso controlado de la sesión, las clases que deseen una referencia a la sesión única la obtendrán llamando al método estático getSessionFactory() de la clase:
public class HibernateUtil { private static final SessionFactory sessionFactory = buildSessionFactory(); private static SessionFactory buildSessionFactory() { try { // Create the SessionFactory from hibernate.cfg.xml return new AnnotationConfiguration().configure() .buildSessionFactory(); } catch (Throwable ex) { System.err.println("Initial SessionFactory creation failed." + ex); throw new ExceptionInInitializerError(ex); } } public static SessionFactory getSessionFactory() { return sessionFactory; } }
A continuación debemos definir unas clases manejadoras que nos proporcione las operaciones CRUD básicas. Aquí podemos ver como cada función obtiene la Sesión correspondiente através de Hibernate Util, y esta sesión nos proporciona los métodos básicos para las operaciones CRUD (Crear, Obtener, Actualizar y Eliminar)(Create, Read, Update and Delete). Es importante destacar que para realizar consultas mas complejas Hibernate proporciona ciertas herramientas como los Criteria o un lenguaje especial llamado HQL. Aquí muestro las funciones básicas de los Manager:
public class ClienteManager { public Cliente add(Cliente cliente) { Session session = HibernateUtil.getSessionFactory().getCurrentSession(); session.beginTransaction(); session.save(cliente); session.getTransaction().commit(); return cliente; } public Cliente update(Cliente user) { Session session = HibernateUtil.getSessionFactory().getCurrentSession(); session.beginTransaction(); session.update(user); session.getTransaction().commit(); return user; } @SuppressWarnings("rawtypes") public Cliente getClienteById(String id) { Session session = HibernateUtil.getSessionFactory().getCurrentSession(); session.beginTransaction(); Criteria crit = session.createCriteria(Cliente.class).add(Restrictions.eq("id",id)); List result=crit.list(); session.getTransaction().commit(); if (result.isEmpty()) return null; else return (Cliente)result.get(0); } public Cliente delete(Long id) { Session session = HibernateUtil.getSessionFactory().getCurrentSession(); session.beginTransaction(); Cliente contact = (Cliente) session.load(Cliente.class, id); if(null != contact) { session.delete(contact); } session.getTransaction().commit(); return contact; } @SuppressWarnings("unchecked") public List list() { Session session = HibernateUtil.getSessionFactory().getCurrentSession(); session.beginTransaction(); List contacts = null; try { contacts = (List)session.createQuery("from Cliente").list(); } catch (HibernateException e) { e.printStackTrace(); session.getTransaction().rollback(); } session.getTransaction().commit(); return contacts; } } public class PedidosManager { public Pedido add(Pedido pedido) { Session session = HibernateUtil.getSessionFactory().getCurrentSession(); session.beginTransaction(); session.save(pedido); session.getTransaction().commit(); return pedido; } public List getPedidoByUserId(int id) { Session session = HibernateUtil.getSessionFactory().getCurrentSession(); session.beginTransaction(); Criteria crit = session.createCriteria(Pedido.class).add(Restrictions.like("cliente_id", id)); List result=crit.list(); session.getTransaction().commit(); return result; } public Pedido getPedidoById(int id) { Session session = HibernateUtil.getSessionFactory().getCurrentSession(); session.beginTransaction(); Criteria crit = session.createCriteria(Pedido.class).add(Restrictions.like("id", id)); List result=crit.list(); session.getTransaction().commit(); return (Pedido) result.get(0); } @SuppressWarnings("unchecked") public List list() { Session session = HibernateUtil.getSessionFactory().getCurrentSession(); session.beginTransaction(); List pedidos = null; try { pedidos = (List) session.createCriteria(Pedido.class).list(); } catch (HibernateException e) { e.printStackTrace(); session.getTransaction().rollback(); } session.getTransaction().commit(); return pedidos; } public Pedido update(Pedido pedido) { Session session = HibernateUtil.getSessionFactory().getCurrentSession(); session.beginTransaction(); session.merge(pedido); session.getTransaction().commit(); return pedido; } }
Procedamos a ver como se emplea esta arquitectura de clases. Este ejemplo sencillo crea un nuevo objeto de la clase Cliente, estableciendo con sus métodos set los distintos atributos de este y finalmente pasándo el objeto al Manager para que se encargue de persistirlo en la base de datos:
Cliente cliente = new Cliente(); cliente.setApellidos(getApellido()); cliente.setNombre(getNombre()); cliente.setDomicilio(getDomicilio()); cliente = clienteManager.add(cliente);
Espero que hayáis disfrutado con estos pequeños ejemplos. Volveré a tratar el tema de los ORM con más profundidad analizando alguna otra herramienta o describiendo características más avanzadas de Hibernate. Aún así os comparto la documentación oficial de la versión 3.5.7 que viene muy bien explicado y con ejemplos
[googleplusauthor]
hola.
me pregunto como programas una consulta select x ejemplo con una tabla principal y una auxiliar????
contratos(anno,mes,id_municipio,valor)
aux_municipios(id,descripcion)
lo pregunto xq el ejemplo q has puesto es el tipico per para algo mas complejo con varias tablas relacionadas, obtener el ultimo dato, hacer inner join entre 5 o 6 tablas a la vez, es q no veo la ventaja.
gracias
saludos
Hola David, lo primero de todo gracias por colaborar.
Supongo que te refieres a ir recorriendo distintas tablas para obtener datos. Como bien dices este ejemplo es el típico relación de 1 a N entre dos tablas. El desarrollo completo tenía mas relaciones, por ejemplo los pedidos además tenían N productos y un estado.
Existen varias formas de hacerlo, pero por ejemplo cuando recuperas a través del EntityManager un elemento hay dos formas de hacerlo, una que sería activando el parámetro lazy, en el cual le dices que la conexión es perezosa y solo tendrá en cuenta para recuperar los atributos simples, no las relaciones, evitando largos join. Si por otro lado desactivas este parámetro para una relación se harán consultas recursivas con join entre las tablas relacionadas obteniendo todos los datos, siendo para tí transparente,.
Es una gran ventaja que al recuperar un elemento te abstraigas de todas las tablas que tienes que recorrer, pero claro por otro lado es pesado ya que Hibernate tiene que ir recorriendo todos los elementos de la base de datos. Depende del objetivo de tu aplicación o tu funcionalidad te merece la pena cargar todo o solo ir cargando los datos que te sean necesarios y recuperar datos relacionados con pequeñas consultas que lanzaras en momentos determinados
Por cierto para el tema de lazy mira los archivos de mapeo del artículo anterior.
Muchas Gracias por leernos y colaborar. Cualquier dudas que tengas no dudes en comentarla 😉
Hola.
Gracias por su comentario. Mucha información, tengo que ir mirando lo que me comentas con detenimiento.
Solo una cosa. Yo utilizo normalmente eclipse 3.4 / 3.7. Existe algún plugin (sé que para myEclipse sí) que me permita hacer los cambios en los ficheros hbm, etc.. cuando hago cambios en la base de datos y que lo haga de forma automática. Las pruebas que he hecho al final me conducen a tener que tocar los ficheros de forma manual.
Gracias.
Salu2
Hola David, para autogenerar los ficheros de mapeo con la base de datos existen las Hibernate Tools. Te dejo el enlace de un blog donde lo cuentan con mucho más detalle:
http://www.adictosaltrabajo.com/tutoriales/tutoriales.php?pagina=hibernateTools
Espero que te sirva.
[…] he decidido mezclar distintos temas de los que he escrito anteriormente: los Mapeos Objeto Relacionales y las Bases de Datos orientadas a Documentos. El patrón de mapeo de datos de la base de datos es […]