Mostrando entradas con la etiqueta Hibernate. Mostrar todas las entradas
Mostrando entradas con la etiqueta Hibernate. Mostrar todas las entradas

jueves, 1 de octubre de 2015

Mapear tabla sin PK con Hibernate

Si nos encontramos con el problema de tener que mapear una tabla con hibernate que no contenga una primary key, tenemos dos opcions:

- Intentar inventarnos una pk si tenemos la suerte que en nuestra tabla hay algun atributo que no se repitan

- O crear una composite Key, cosa que explicaré a continuación

Se trata de algo muy sencillo, simplemente debemos elegir dos atributos de nuestra tabla, que sean de interés para nostros y para los datos que estamos analizando y utilizarlos como claves para las entradas, para ello modificaremos el xml de mapeo de la tabla en cuestión (hbm.xml) y introduciremos el tag .






Importante : La clase .java del mapeo debe implementar Serializable (si es que no lo hacía ya...)





lunes, 27 de abril de 2015

Inserts con clave primaria autoincremental en Hibernate y SQL Server

Algunas veces me he encontrado que teniendo que realizar un insert autoincremental en una Base de Datos SQL Server, el típico session.save(Object) ha fallado y no sabemos porque. Para eso utilizo el siguiente método como alternativa para realizarlos, 

viernes, 4 de abril de 2014

Hibernate: Inserts en la clase DAO

Vamos a realizar un insert des de una clase DAO.

En primer lugar es una buena idea crear un pequeño método que nos devuelva el objeto en caso de tenerlo previamente en la base de datos. De esta manera podemos decidir si en vez de hacer un insert le hacemos un update.

Vamos a ver como hacer este método con un ejemplo :

public Umbrales getUmbrales(int idUser){  

 Umbrales umbrales = null;  
 try{   
  iniciaOperacion();   
  Criteria criteria = sesion.createCriteria(Umbrales.class);   
  criteria.add(Restrictions.eq("idUsuari", idUser));   
  umbrales = (Umbrales)criteria.uniqueResult();
} catch(HibernateException he){   
    manejaExcepcion(he);
    throw he;  
}finally{   
    sesion.close();}   
return umbrales;
}

Vamos a comentarlo de un modo rápido. Añadimos un criteria con el id de usuario que contiene este objeto llamado Umbrales (es un ejemplo, extrapolar a lo que cada uno necesite, no importa que es exactamente Umbrales). Una vez hecho esto se devuelve un único objeto de la BD  con criteria.uniqueResult(); (entendamos que un usuario solo puede tener un objeto Umbrales en nuestra BD y por tanto idUsuario funciona como identificador único). El modificador del método puede ser public o private según nuestras necesidades de llamar a este método fuera de la clase.

Una vez hecho esto, implementamos el método guardar de la siguiente manera:

public boolean guardarUmbrales(int idUsuari,float dispOptima,float dispWaring,float dispCritical){

  boolean rc=false;
  Umbrales umbralNuevo = 
  new Umbrales(idUsuari,dispOptima,dispWaring,dispCritical);
  Umbrales umbralGuardado = getUmbrales(idUsuari);
  if(umbralGuardado == null){
    rc = insertUmbral(umbralNuevo);
  }else{
    rc = updateUmbrales(umbralNuevo);
  }
 return rc;
}

Este método es público ya que puede ser llamado des de cualquier lado. Vamos a comentar este método : por parámetros recibiremos un seguido de variables que utilizaremos para montarnos el objeto nuevo Umbrales, esto no es del todo necesario ya que podríamos recibir por parámetro directamente el objeto ya instanciado. A continuación realizamos una llamada al método getUmbrales() que hemos creado anteriormente, este nos devolverá un objeto en casa de existir previamente o un null en caso de que no existe ningún objeto en la BD con ese id de usuario, en base a esto decidimos, si es null crearemos una nueva entrada y si ya existe realizaremos un update. Los métodos que haran estas tareas son implementados con modificadores de acceso private ya que no deben ser llamados nunca des de fuera de esta clase, y si debe ser llamado guardarUmbrales() (que contiene la lógica de decisión de que hacer), los métodos son los siguientes:

private boolean insertUmbral(Umbrales umbral){
  boolean rc=false;
  try{
   iniciaOperacion(); 
   sesion.save(umbral);
   tx.commit();
   rc=true;
  }catch(HibernateException he){
   manejaExcepcion(he); 
   throw he; 
  }finally{
   sesion.close(); 
  }
 return rc;
}

private boolean updateUmbrales(Umbrales umbral){
  boolean rc=false;
  try{
    iniciaOperacion(); 
    sesion.update(umbral); 
    tx.commit(); 
    rc=true;
  }catch(HibernateException he){
    manejaExcepcion(he); 
    throw he; 
  }finally{
    sesion.close(); 
  }
  return rc;

}

Cada uno de los métodos retornan una variable rc para verificar que las operaciones han ido correctamente o no, a modo que podamos tener un control de los resultados.


lunes, 7 de octubre de 2013

Hibernate: Creación de la clase DAO

Vamos a profundizar un poco mas en la creación de clase DAO. Estas clases se crean con el objetivo de dotar a la aplicación de una capa que se encargue del acceso a la BD proporcionando así abstracción e independencia del resto de las capas de servicio de negocio de la aplicación.

La clase DAO (Data Acces Object) será la encargada de realizar las acciones que necesitemos sobre la Base de Datos (Insterts, updates, deletes...)

En el post anterior ya realizamos una clase DAO, ahora vamos a ver como aplicar los criterios de diversas formas a nuestra consulta.

En primer lugar hablaremos de Criteria. Criteria es una clase incluida en el paquete de hibernate que nos permitirá realizar nuestra consulta de una forma sencilla.

Instanciamos el objeto criteria pasando la clase donde se aplicaran las restricciones como atributo:

Criteria criteria = sesion.createCriteria(DWH_DIA.class);

Recordar que previamente hemos creado el objeto sesion mediante :

sesion = HibernateUtil.getSessionFactory().openSession();

Una vez hecho esto, podemos empezar a añadirle condiciones a nuestro objeto criteria, por ejemplo decirle que id queremos buscar en nuestra consulta :

criteria.add(Restrictions.eq("idTest", 120));

o incluso marcarle un order by:

criteria.addOrder(Order.asc("Fecha"));

Una vez aplicados todos los criterios necesarios a nuestra consulta, bastará con listarla:

listaDatos=criteria.list();

Otro metodo interesante es aplicar varios valores a un mismo campo como criterio de consulta, en este caso :

Disjunction disjunction = Restrictions.disjunction();
disjunction.add(Restrictions.eq("id", 120));
disjunction.add(Restrictions.eq("id", 121));


Finalmente se aplica el objecto disjunction a nuestro criterio de selección:

criteria.add(disjunction);


De esta manera se aplicarían los valores 120 y 121 al campo id de nuestra consulta como criterio de selección.


Otra opción para realizar la consulta seria aplicar una consulta SQL creada mediante el típico String en java, en este caso, una vez escrita la consulta, haremos :

Query query = sesion.createQuery(sql);

Y posteriormente iteraremos sobre los resultados que se produzcan para tratarlos de la forma que nos convenga, por ejemplo los recogeremos en un Objet[]

for(Iterator it=query.iterate();it.hasNext();){
Object[] row = (Object[]) it.next();
}


miércoles, 4 de septiembre de 2013

Hibernate: Primeros Pasos. Ejemplo

Hibernate es un framework open source que nos facilitara mucho la tarea de realizar una capa de persistencia de datos en nuestra aplicacion mediante el mapeo de clases de una base de datos relacional.

En este tutorial mostraremos un mix entre realizar el esqueleto mediante el asistente hibernate tool y la creacion de ciertos componentes a mano, evidentemente cada uno puede utilizar luego un metodo u otro, pero en este caso, y a mi criterio, considero que esta es la mejor manera de realizar el desarrollo.

En primer lugar vamos a bajarnos hibernate tool en nuestro eclipse, en mi caso se trata de una versión juno, por lo que deberemos ir a la pestaña Help --> Eclipse marketplace y en el buscador poner Hibernate.
Hibernate tool forma parte de el paquete de herramientas JBoss en su versión para eclipse juno por lo que seleccionaremos este.


Una vez se despleguen todos los paquetes seleccionamos el que nos interesa


Nos pedirá reiniciar eclipse y ya tendremos nuestro asistente de Hibernate instalado.

El ejemplo lo desarrollaremos en un proyecto para J2EE, por lo que  crearemos uno "Dinamic Web Project" de ejemplo.

Una vez creado añadiremos los jars necesarios para hibernate, una vez descargado el zip con todos los jars de Hibernate veremos que los jars necesarios los encontraremos en lib/requiered. Todos ellos los añadiremos a WEB-INF/lib y luego al classpath del proyecto.

Antes de continuar necesitamos tener el jar para la conexion a la BD y añadirlo a nuestro classpath. En mi caso voy a conectarme a una BD Sql Server remota y voy a utilizar  JTDS.



Seguidamente vamos a crear el archivo de configuración de Hibernate con el asistente que acabamos de bajar, para ello, click derecho sobre nuestro proyecto New --> Hibernate configuration File


Seleccionamos que se guarde en la raíz de la carpeta src de nuestro proyecto, y seguidamente rellenamos los campos necesarios, en este caso se puede ver en la imagen como los he rellenado para mi proyecto (recordemos que utilizo una BD SQL server en remoto para este ejemplo). Seleccionamos tambien Create a console configuration

En la siguiente pantalla se puede configurar todo lo relacionado con nuestro hibernate (version, conexión a base de datos...) yo lo dejo todo por defecto pero me aseguro que en la ventana del classpath este incluido mi jar jstd, si no estuviese, fallaría al intentar conectarse.

Una vez terminado, veremos como se nos ha generado el archivo de configuración de hibernate, si queremos curiosear veremos que se trata de una estructura clásica de xml con todos los datos necesarios.

En el siguiente apartado vamos a mapear una tabla de la base de datos, esto se puede hacer a mano o con el asistente, en mi caso voy a proceder a mano a partir de aquí porque quiero tener un control total sobre el código que se genere, cada uno puede escoger la opción que mejor le convenga.

La tabla a mapear es una llamada Telefons que tiene la siguiente estructura :




En primer lugar, y por comodidad de tenerlo todo ordenado, creo un package llamado mapeos donde pondré todas las clases mapeadas, a continuación creo una clase y la escribo usando la convención de nombres Java Beans para getters y setters y visibilidad privada para sus atributos. No es obligatorio hacerlo así pero si recomendable.






De esta manera, la clase queda así:

public class Telefons implements Serializable{

private int id;
private String movil;
private String nom;
private String descripcio;
private String dataAlta;
private String dataModificacio;
private boolean bsms;

public Telefons() {

}

public Telefons(String movil, String nom, String descripcio,

String dataAlta, String dataModificacio, boolean bsms) {
this.movil = movil;
this.nom = nom;
this.descripcio = descripcio;
this.dataAlta = dataAlta;

this.dataModificacio = dataModificacio;
this.bsms = bsms;
}

public int getId() {
return this.id;
}

private void setId(int id) {
this.id = id;
}

public String getMovil() {
return this.movil;
}

public void setMovil(String movil) {
this.movil = movil;
}


public String getNom() {
return this.nom;
}

public void setNom(String nom) {
this.nom = nom;
}

public String getDescripcio() {
return this.descripcio;
}

public void setDescripcio(String descripcio) {
this.descripcio = descripcio;
}

public String getDataAlta() {

return this.dataAlta;

}
public void setDataAlta(String dataAlta) {
this.dataAlta = dataAlta;
}

public String getDataModificacio() {
return this.dataModificacio;
}

public void setDataModificacio(String dataModificacio) {
this.dataModificacio = dataModificacio;
}

public boolean isBsms() {
return this.bsms;
}

public void setBsms(boolean bsms) {
this.bsms = bsms;
}
}


A destacar tenemos que se debe crear un constructor sin argumentos, esto es obligatorio ya que Hibernate creará instancias de esta clase por reflexión.

A continuación vamos a crear el archivo de mapeo, para ello click derecho new--> othres--> y crearemos un Hibernate XML Mapping file asociado a nuestra clase Telefons. El archivo debe quedar de esta manera :

<hibernate-mapping>
    <class name="mapeo.Telefons" table="TELEFONS">
        <id name="id" type="int">
            <column name="ID" />
            <generator class="increment" />
        </id>
        <property name="movil" type="java.lang.String">
            <column name="MOVIL" />
        </property>
        <property name="nom" type="java.lang.String">
            <column name="NOM" />
        </property>
        <property name="descripcio" type="java.lang.String">
            <column name="DESCRIPCIO" />
        </property>
        <property name="dataAlta" type="java.lang.String">
            <column name="DATAALTA" />
        </property>
        <property name="dataModificacio" type="java.lang.String">
            <column name="DATAMODIFICACIO" />
        </property>
        <property name="bsms" type="boolean">
            <column name="BSMS" />
        </property>
    </class>
</hibernate-mapping>


El tag <generator> como increment hará que Hibernate nos genere los id de forma automática e incremental. Si la base de datos tiene el campo id definido como clave primaria, ella será la encargada de generar esos id para el campo si es que vamos a insertar un nuevo objeto. Por lo tanto, en vez de poner "incremental" en el campo "generator", pondremos "native" para que podamos realizar los inserts


Ahora nos dirigimos a nuestro archivo de configuración .cfg y le decimos que hemos creado un nuevo mapeo, esto se hace colocando el tag :


<mapping resource="mapeo/Telefons.hbm.xml"/>


Dentro de la etiqueta : <session-factory>


Otra cosa que puede ser interesante indicar en este archivo de propiedades es el pool de conexiones, con el tag <property name="connection.pool_size">1</property>, pero de momento no es imprescindible.


Hasta aquí ya tenemos el trabajo hecho, evidentemente esto se puede hacer extensible a tantas tablas como queramos, hasta tener la base de datos completamente mapeada.


Ahora vamos a empezar con el manejo de los objetos Telefons con nuestra base de datos.


Antes de nada, debemos incorporar al classpath de nuestro proyecto los jars de hibernate, que es algo que todavía no habíamos hecho, para ello nos dirigimos a su página y descargamos el zip de la última versión, a día de hoy es este. Abrimos el zip y buscamos en la carpeta lib una llamada required, cogemos todos estos jars y los añadimos al classpath de nuestro proyecto.


Ahroa ya podemos realizar la implementación de nuestra interficie DAO entre nuestra aplicación y la base de datos.

En primer lugar, crearemos una clase común a todos nuestras DAO's(en este caso solo uno) que llamaremos HibernateUtil, tendrá esta pinta :


public class HibernateUtil {
private static final SessionFactory sessionFactory;   

    static 
    { 
        try { 
          sessionFactory = new Configuration().configure().buildSessionFactory(); 
        } catch (HibernateException he) { 
           System.err.println("Ocurrió un error en la inicialización de la SessionFactory: " + he); 
           throw new ExceptionInInitializerError(he); 
        } 
    }  

    public static SessionFactory getSessionFactory() 
    { 
        return sessionFactory; 
    } 

}


Apunte : en la versión 4 de hibernate, el método .buildSessionFactory() esta deprecated, la alternativa la podemos obtener de StackOverFlow


Una vez hecho esto, creamos otra llamada TelefonsDAO, que sera la encargada de realizar las acciones propiamente dichas. En este caso vamos a hacer métodos para guardar, actualizar, borrar y obtener uno a todos los elementos de la tabla. La clase quedará así :



public class TelefonsDAO {

private Session sesion;
private Transaction tx;

private void iniciaOperacion() throws HibernateException{
   sesion = HibernateUtil.getSessionFactory().openSession();
   tx = sesion.beginTransaction();
}

private void manejaExcepcion(HibernateException he) throws HibernateException{
   tx.rollback();
   throw new HibernateException("Ocurrió un error en la capa de acceso a datos", he);
}

public int guardaTelefono(Telefons telefons){ 
   int id = 0;  
   try { 
       iniciaOperacion(); 
       id = (Integer)sesion.save(telefons); 
       tx.commit(); 
   }catch(HibernateException he) { 
       manejaExcepcion(he);
       throw he; 
   }finally { 
       sesion.close(); 
   }  
   return id; 
}

public void actualizaTelefono(Telefons telefons) throws HibernateException { 
   try{ 
       iniciaOperacion(); 
       sesion.update(telefons); 
       tx.commit(); 
   }catch (HibernateException he) { 
       manejaExcepcion(he); 
       throw he; 
   }finally { 
       sesion.close(); 
   } 
}

public void eliminaTelefons(Telefons telefons) throws HibernateException { 
   try { 
       iniciaOperacion(); 
       sesion.delete(telefons); 
       tx.commit(); 
   } catch (HibernateException he){ 
       manejaExcepcion(he); 
       throw he; 
   }finally { 
       sesion.close(); 
   } 
}

public Telefons obtenTelefonsPorID(int idTelefon) throws HibernateException{ 
Telefons tlf = null;  
   try { 
       iniciaOperacion(); 
       tlf = (Telefons) sesion.get(Telefons.class, idTelefon); 
   } finally { 
       sesion.close(); 
   }  
   return tlf; 
}

public List<Telefons> obtenTodosTelefons() throws HibernateException { 
   List<Telefons> listaTelefons = null;  
   try { 
       iniciaOperacion(); 
       listaTelefons = sesion.createQuery("from Telefons").list(); 
   }finally { 
       sesion.close(); 
   }  

   return listaTelefons; 
}
}

El package de mi proyecto queda de esta manera :





Con esto ya tendremos preparada nuestra capa de acceso a los datos. Ahora solo hemos deinstanciar objetos Telefons y pasárselo a los métodos de la clase TelefonsDAO






En próximos posts iré ampliando mas información sobre Hibernate