---
# System prepended metadata

title: 'ORM''s: Hibernate'
tags: [UF2 Persistència en BDR-BDOR]

---

# ORM's: Hibernate

## ORM: Què són? Quins n'hi ha?

ORM són les sigles corresponents a **Object Relational Mapping**

Les tècniques d’ORM fan ús de descripcions i metadades per tal d’establir una correspondència entre les dades primitives de cada model i les seves estructures: 
* taules vs classes/objectes.
* camps vs atributs (de la classe).
* claus principals vs identificadors.

A més necessitarem un **mecanisme de persistència dels objectes** de forma que aquests puguin existir permanentment en memòria, es puguin rastrejar i que qualsevol canvi en un atribut pugui ser arrossegat de forma permanent a la memòria.

![ORM](https://hackmd.io/_uploads/rJHxjXWp6.svg)
Alguns ORM's:

* PHP: Doctrine, Eloquent (per Laravel), Propel, ...
* Java: Hibernate
* Python: SQL Alchemy

Pel que fa a SQL Alchemy, aquí teniu l'enllaç a la pàgina del Xavi Quesada respecte a aquest ORM: [SQL Alchemy](https://hackmd.io/@JdaXaviQ/HyqU6GBoi)

## Avantatges i inconvenients dels ORMs

Alguns avantatges:

* Ajuden a reduir el temps de desenvolupament.
* Independitzar la capa de negoci (lògica de negoci) de la capa d'accés a dades.
* Són independents del SGDB relacional emprat. Sols duen a terme el mapatge BD vs objectes.
* Disposen d'un llenguatge propi per fer consultes (sobre els objectes persistits o a persistir).
* Fomenten la reutilització, l'escalabitat i la portabilitat del codi.

Per citar algun inconvenient podem esmentar la lentitud. Qualsevol consulta que es faci a la base de dades necessitarà ser transformada al llenguatge propi de consulta que tingui l'eina, llegir tot seguit els registres i a partir d'aquí crear els objectes que manipularà posteriorment l'aplicació.

## Hibernate

Com ja hem comentat Hibernate és un ORM propi de java el qual declara les relacions mitjançant dos mecanismes:

* Fitxers declaratius XML.
* Anotacions a les classes java (javabeans per ser més exactes).

Hibernate ofereix un llenguatge OQL (Object Query Language) anomenat HQL (Hibernate Query Language) de forma que és el propi ORM el que fa la traducció d’HQL cap al propi de cada base de dades.

## Arquitectura d'hibernate

![image](https://hackmd.io/_uploads/By-xrVWT6.png)
Font: [jboss - hibernate](https://docs.jboss.org/hibernate/orm/3.5/reference/es-ES/html/architecture.html)

1. L’aplicació crea objectes, els quals romanen de forma “volàtil” a la memòria. Es coneixen com objectes transient, transitoris.
2. Per emmagatzemar aquests objectes a la base de dades, hibernate utilitza objectes sessió (Session) els quals s'encarreguen de dialogar amb el motor d'hibernate. També serveixen per recuperar objectes persistits a la base de dades.
3. Les sessions s'obren i tanquen, per tant actuen d'una forma semblant a les connexions amb bases de dades que hem vist fins ara (cas de les connexions JDBC a java o els connectors a python).
4. Dins la capa d'hibernate conviuen sessions i transaccions. 
5. Fixeu-vos que entre la capa d'hibernate i la capa de base de dades s'utilitzen APIs pròpies de java com JNDI, JDBC i JTA.

Recordeu els estats de persistència de qualsevol objecte:

* Transient
* Persistent
* Detached
* Removed 

![image](https://hackmd.io/_uploads/H1-M9V-6T.png)
Font: [different-states-of-an-object-in-jpa](https://jstobigdata.com/jpa/different-states-of-an-object-in-jpa/)

## Extensió del visual studio i creació d'un nou projecte

La forma més adequada per començar a treballar amb hibernate és creant un nou projecte Maven.

Com ja hem vist anteriorment, Maven és un gestor de dependències i una eina molt útil per poder construir projectes amb java. Utilitzarem Maven per poder incorporar les dependències d'hibernate i mariadb o mysql.

En cas que no tingueu configurat el visual studio, cal que seguiu aquests passos. Si ja el teniu configurat ometeu aquesta part. 

En primer lloc cal instal·lar el següent extension pack:

![image](https://hackmd.io/_uploads/ryNzLHbpT.png)

Aquest pack inclou altres extensions com **Maven for java**, la qual serà necessària d'ara en endavant.


Per poder crear un nou projecte fem CTRL + Shift + P i un cop aparegui la barra de comandes a la part superior, escriurem maven. D'entre les opcions escollirem **Maven: New Project**

![image](https://hackmd.io/_uploads/S1VxtrZa6.png)

No escollirem cap arquetip:

![image](https://hackmd.io/_uploads/SJhrYHZpa.png)

Anem seguint els passos i introduint la informació com el group id del projecte (prèmer Enter a l'acabar):

![image](https://hackmd.io/_uploads/Hy_YPTmP1l.png)


El nom del projecte o de l'artefacte (prèmer Enter a l'acabar):

![image](https://hackmd.io/_uploads/B19ovp7PJx.png)


A continuació ens demanarà que seleccionem la carpeta de destí on estarà el nostre projecte:

![image](https://hackmd.io/_uploads/Hyf-qrZp6.png)

Si tot ha anat bé, veurem a la part inferior el següent missatge:

![image](https://hackmd.io/_uploads/BJPNcS-6p.png)

I a l'explorador si despleguem el projecte podrem apreciar el fitxer pom.xml, el qual veurem que té un paper fonamental:

![image](https://hackmd.io/_uploads/SJ-bdaXP1e.png)



## Edició del pom.xml i dependències necessàries

D'una banda afegirem la dependència corresponent a hibernate, la qual es pot trobar al web [mvn repository - hibernate](https://mvnrepository.com/artifact/org.hibernate.orm/hibernate-core/6.4.4.Final). En el moment d'escriure aquestes notes la versió és la 6.4.4, però de ben segur n'hi haurà de més recents:

```
<!-- https://mvnrepository.com/artifact/org.hibernate.orm/hibernate-core -->
<dependency>
    <groupId>org.hibernate.orm</groupId>
    <artifactId>hibernate-core</artifactId>
    <version>6.4.4.Final</version>
</dependency>
```

Per altra banda necessitarem afegir la dependència corresponent al connector del SGDB que volguem utilitzar. En el cas específic de mariadb la dependència com ja sabeu és:

```
<!-- https://mvnrepository.com/artifact/org.mariadb.jdbc/mariadb-java-client -->
<dependency>
    <groupId>org.mariadb.jdbc</groupId>
    <artifactId>mariadb-java-client</artifactId>
    <version>3.5.1</version>
</dependency>
```

La podreu trobar igualment a [client java per mariadb - maven](https://mvnrepository.com/artifact/org.mariadb.jdbc/mariadb-java-client/3.5.1)

És important visitar regularment aquest web per comprovar que agafem la darrera versió més estable.

En aquest enllaç teniu una versió de l'arxiu:
[pom.xml](https://drive.google.com/file/d/1p1bXck87fFPBcTNS1muI_UcG1OHfMB-0/view?usp=sharing)

## Parts d'un projecte amb hibernate

A grans trets tot projecte haurà de tenir:

* **HibernateUtil** és un arxiu que conté:

    * La **interfície Configuration**, la qual configura hibernate a partir dels fitxers xml (cfg i *.hbm).
    * A partir d'una instància de Configuration es crea la **SessionFactory** o factoria de sessions. Com els patrons de factoria, SessionFactory empra una interfície compartida pels diferents fils d'execució de l'aplicació, de tal forma que **en una aplicació que accedeix a una única base de dades, només hi haurà una única SessionFactory**. Si l'aplicació necessita accedir a més d'una base de dades, llavors hi haurà més d'una SessionFactory.
    * Aquest comportament segueix el patró creacional anomenat **singleton**, que garanteix l'existència d'una única instància (amb un punt d'accés global) per a cada base de dades. En podeu trobar més informació sobre el seu funcionament a [**Singleton Pattern**](https://refactoring.guru/es/design-patterns/singleton/java/example).
    * **Hibernate.cfg.xml** és un XML que conté la cadena de connexió a la base de dades, a més d'altres detalls.
    * Les classes tipus **javabean/POJO** (Plain Old Java Object) amb els atributs que caracteritzen el model de dades.
    * Depenent de com implementem, podrem fer sevir arxius de mapatge del tipus **<nom_classe>.hbm.xml**. Cada classe que s'hagi de relacionar amb una entitat de la base de dades haurà de tenir un arxiu com aquest. Una altra alternativa es fer servir **anotacions** i **estalviar-nos fer servir aquests arxius**.

    * La classe o classes d'aplicació amb el corresponent **static void main** encarregat d'orquestrar les accions d'obrir sessions, gestionar transaccions, instanciar els objectes a persistir, etc.

![hiber.drawio](https://hackmd.io/_uploads/B1dLbP-pa.png)


## El fitxer hibernate.cfg.xml

Els IDE com Eclipse o NetBeans disposen d'assistents per crear aquest arxiu XML a partir dels detalls de connexió a la base de dades, com és la cadena de connexió, usuari, password, etc.

**Aquest arxiu cal que estigui situat dins una carpeta anomenada resources**. Per exemple:

![image](https://hackmd.io/_uploads/SJ6wErXTa.png)

Un exemple d'arxiu podria ser el següent, on ens estem connectant a una base de dades local mysql anomenada cinema:

```
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <session-factory>

        <!-- Propiedades de la conexión -->

        <!-- Driver JDBC -->
        <property name="connection.driver_class">org.mariadb.jdbc.Driver</property>

        <!-- Conexión. Añadir ?createDatabaseIfNotExist=true para crear la BBDD  -->
        <property name="connection.url">jdbc:mariadb://localhost:3306/tasks</property>

        <!-- Usuario y password de la BBDD -->
        <property name="connection.username">root</property>
        <property name="connection.password">1234</property>

        <!--  dialecto dentro del conector. Importante para claves ajenas-->
        <property name="dialect">org.hibernate.dialect.MySQLDialect</property>

        <!-- Configuraciones adicionales -->

        <!-- JDBC connection pool Conexiones concurrentes -->
        <property name="connection.pool_size">5</property>

        <!-- Una sesion de trabajo por Thread-->
        <property name="current_session_context_class">thread</property>


        <!-- Informa de las operaciones "reales" SQL. Interesante en desarrollo -->
        <property name="show_sql">true</property>

        <!-- Mantenimiento de la BBDD -->

        <property name="hbm2ddl.auto">update</property>

        <!-- opciones de hbm2dll:
        create : Borra y crea SIEMPRE la base de datos
        update : Mantiene los datos, actualizando la estructura de la BBDD. 
        create-drop : Crea todo, y al finalizar el programa lo borra
        validate: comprueba que las especificaciones del mapeo son validas con el diseño relacional de la BBDD
        -->

        <!-- Ficheros de mapeo. Pueden combinarse-->
      
        <!-- Mapeo DENTRO DE LA CLASE -->
      
    </session-factory>
</hibernate-configuration>
```

Les propietats d'aquest XML més interessants són:

* Propietats de la connexió:

    * **Driver class**: si és per connectar amb MySQL o un altre SGDB.
    * **Connection URL, username i password**: per indicar la BBDD a la que ens connectem, usuari i password (amb permissos).
    * **Connection pool**: nombre de connexions concurrents (mentre es fa servir l'aplicació).
    * **hbm2ddl.auto**: hbm2ddl serveix per generar l'esquema (de la base de dades) a partir de mapejar les entitats (a persistir). Opcions:
        * **create**: esborra l'esquema/estructura de la base de dades existent (al SGDB) i el crea de nou a partir de com estan definides les classes (vegeu el següent enllaç per a més informació: [Database schema generation](https://docs.jboss.org/hibernate/orm/current/userguide/html_single/Hibernate_User_Guide.html#schema-generation))
        * **update**: si hi ha cap canvi entre l'esquema de base de dades i les classes, actualitzarà l'estructura de la base de dades. Respecta les dades prèviament emmagatzemades a la base de dades.
    * Per últim, cap al final hi ha una secció per incorporar els fitxers de mapatge, és a dir, els hbm.xml i la mapping class. Així, suposem que volem mapejar l'entitat Actors. Per fer-ho posaríem el següent:

Dues possibilitats de mapeig (com veurem en endavant):

```
       <!-- Ficheros de mapeo. Pueden combinarse-->
        <mapping resource="Tasks.hbm.xml"/>

        <!-- Mapeo DENTRO DE LA CLASE -->
        <mapping class="model.Tasks" />

```

## La classe HibernateUtil

Aquesta serà una classe que incorporem manualment i que normalment tindrà un codi semblant a aquest:

```
package com.iticbcn.hibernate;

import org.hibernate.SessionFactory;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Configuration;
public class HibernateUtil {
//Para asegurar que la clase no pueda ser instanciada nuevamente 
//se regula el alcance del constructor con el atributo private
    private static final SessionFactory sessionFactory = buildSessionFactory();
    
    private static SessionFactory buildSessionFactory(){
        try{
            return new Configuration()
                    .configure()
                    .buildSessionFactory(new StandardServiceRegistryBuilder()
                    .configure()
                    .build());
        } catch (Throwable ex) {
            System.err.println("Initial SessionFactory creation failed."+ex);
            throw new ExceptionInInitializerError(ex);
        }
    }
    
    public static SessionFactory getSessionFactory(){
        return sessionFactory;
    }
}
```

## La classe Aplicació

Ja per acabar, la classe aplicació ha de crear la sessió i fer les operacions pròpies de mostrar dades o persistir objectes.

Aquesta classe és molt simple com podeu veure i es limita a fer com un "Hola Món". Més endavant veurem quines possibilitats dóna:

```
package com.hibernate.iticbcn;

import org.hibernate.SessionFactory;
import org.hibernate.Session;

public class Main 
{
    public static void main( String[] args )
    {
        SessionFactory sesion = HibernateUtil.getSessionFactory();

        Session session = sesion.openSession();

        session.beginTransaction();

        System.out.println("Hola desde Hibernate");

        session.getTransaction().commit();

        session.close();

    }
}
```

NOTA: Feu una ullada a [Java Debugging](https://code.visualstudio.com/docs/java/java-debugging) i implementeu-lo al vostre projecte en cas necessari.

En aquest cas, un arxiu launch.json possible seria aquest:

```
{
    // Utilitzeu IntelliSense per aprendre sobre els atributs possibles.
    // Passeu el cursor per sobre per veure les descripcions dels atributs existents.
    // Per a més informació, visiteu: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "type": "java",
            "name": "App",
            "request": "launch",
            "mainClass": "${file}"
        },
        {
            "type": "java",
            "name": "App",
            "request": "launch",
            "mainClass": "com.hibernate.iticbcn.App",
            "projectName": "hiber1"
        }
    ]
}
```

A partir d'aquí fent el run de la classe App ens hauria de mostrar el següent output, confirmant que en efecte l'ORM és operatiu al projecte:

```
PS C:\Users\accesadades\gitcode\M06-UF2-Hibernate>  c:; cd 'c:\Users\accesadades\gitcode\M06-UF2-Hibernate'; & 'C:\Users\antot\.vscode\extensions\redhat.java-1.38.0-win32-x64\jre\17.0.13-win32-x86_64\bin\java.exe' '@C:\Users\antot\AppData\Local\Temp\cp_cw5nk1bfmy8b4gfoqaevynsqs.argfile' 'com.iticbcn.hibernate.Main' 
12:41:57.803 [main] DEBUG org.mariadb.jdbc.message.server.OkPacket -- Database change: is 'tasks'
12:41:57.803 [main] DEBUG org.mariadb.jdbc.client.impl.StandardClient -- execute query: set sql_mode=CONCAT(@@sql_mode,',STRICT_TRANS_TABLES'),session_track_system_variables = CONCAT(@@global.session_track_system_variables,',transaction_isolation'),NAMES utf8mb4
12:41:57.803 [main] DEBUG org.mariadb.jdbc.message.server.OkPacket -- System variable change:  character_set_client = utf8mb4
12:41:57.803 [main] DEBUG org.mariadb.jdbc.message.server.OkPacket -- System variable change:  character_set_connection = utf8mb4
12:41:57.803 [main] DEBUG org.mariadb.jdbc.message.server.OkPacket -- System variable change:  character_set_results = utf8mb4
12:41:57.803 [main] DEBUG org.mariadb.jdbc.client.impl.StandardClient -- execute query: set autocommit=0
12:41:57.803 [main] DEBUG org.mariadb.jdbc.message.server.OkPacket -- System variable change:  autocommit = OFF
12:41:57.838 [main] DEBUG org.mariadb.jdbc.client.impl.StandardClient -- execute query: SELECT @@character_set_database, @@sql_mode
12:41:57.854 [main] DEBUG org.mariadb.jdbc.client.impl.StandardClient -- execute query: select @@lower_case_table_names
12:41:57.854 [main] DEBUG org.mariadb.jdbc.client.impl.StandardClient -- execute query: set autocommit=1
12:41:57.869 [main] DEBUG org.mariadb.jdbc.message.server.OkPacket -- System variable change:  autocommit = ON
12:41:58.246 [main] DEBUG org.mariadb.jdbc.client.impl.StandardClient -- execute query: set autocommit=0
12:41:58.260 [main] DEBUG org.mariadb.jdbc.message.server.OkPacket -- System variable change:  autocommit = OFF
Hola desde Hibernate
12:41:58.260 [main] DEBUG org.mariadb.jdbc.client.impl.StandardClient -- execute query: set autocommit=1
12:41:58.260 [main] DEBUG org.mariadb.jdbc.message.server.OkPacket -- System variable change:  autocommit = ON
```

## Mapatge d'una classe tasques

Tot seguit s'explicarà com fer que hibernate ens creï una taula a partir d'una entitat java.

#### Creació d'un POJO i el paquet model

Es pot fer de dues maneres: com una classe java amb constructor, getters i setters o fent servir anotacions. Més endavant explicarem l'opció de fer servir anotacions ja que a la llarga resultarà més còmoda.

Així, dins el directori/paquet main/java/com/hibernate/iticbcn, o dins el directori que tingueu creat a l'efecte, procedirem a crear la carpeta **model**. Aquesta carpeta serà la que contindrà les classes que constitueixen el model de la nostra aplicació. 

Dins model crearem una classe java anomenada tasks, la qual tindrà el següent codi:

![image](https://hackmd.io/_uploads/rJrhtAS6a.png)

```
package com.iticbcn.hibernate.model;
import java.io.Serializable;

public class tasks implements Serializable{
    private int idTask;
    private String descTask;
    private int numHours;
    private boolean finalitzada;
    
    public tasks(){}
    
    public tasks(String descTask, int numHours, boolean finalitzada) {
        this.descTask = descTask;
        this.numHours = numHours;
        this.finalitzada = finalitzada;
    }

    public int getIdTask() {
        return idTask;
    }

    public void setIdTask(int idTask) {
        this.idTask = idTask;
    }

    public String getDescTask() {
        return descTask;
    }

    public void setDescTask(String descTask) {
        this.descTask = descTask;
    }

    public int getNumHours() {
        return numHours;
    }

    public void setNumHours(int numHours) {
        this.numHours = numHours;
    }

    public boolean isFinalitzada() {
        return finalitzada;
    }

    public void setFinalitzada(boolean finalitzada) {
        this.finalitzada = finalitzada;
    }

    @Override
    public String toString() {
        return "tasks [idTask=" + idTask + ", descTask=" + descTask 
        + ", numHours=" + numHours + ", finalitzada=" + finalitzada + "]";
    }

}
```

Com veieu aquesta classe implementa la interfície serialitzable, de la qual ja vam parlar [aquí](https://hackmd.io/@TTalens/BkzTVNRQp), a més de disposar d'un constructor per defecte. Podem dir doncs que aquesta classe és un **POJO (Plain Old Java Object)**, definint un objecte de negoci concret (tasques).

#### Creació del fitxer de mapatge

Dins la carpeta resources cal crear un arxiu anomenat **tasks.hbm.xml**, el qual serà l'encarregat de definir el mapatge entre l'entitat (la classe java) i la taula (encara no creada).

```
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
    <class name="com.iticbcn.hibernate.model.tasks" table="tasks">
        <id name="idTask" column="idTask">
            <generator class="identity"/>
        </id>
        <property column="descTask" name="descTask" />
        <property column="numHours" name="numHours" />
        <property column="finalitzada" name="finalitzada" />
    </class>
</hibernate-mapping>
```

En el class name posem la ruta al paquet on tenim la classe a mapejar i a la dreta, a table, posem el nom que tindrà la taula dins la base de dades. Seguint aquesta mateixa lògica, els noms d'atributs que veieu a l'esquerra dins les propietats corresponen als noms que tenen a la classe, mentre que els noms de la dreta corresponen als noms que tenen o tindran a la taula.

Qualsevol canvi de noms tant a l'entitat com a la taula (un cop estigui creada) haurà d'estar reflectit a aquest fitxer.

Fixeu-vos que amb **generator-class = "identity"** el que fem és dir-li al SGDB que aquest camp sigui un auto incremental, de tal forma que no l'haguem d'informar explícitament i sigui el propi motor de la base de dades el que l'obtingui quan persistim un objecte.

Per últim: **quan fem servir anotacions a les entitats, no necessitem crear aquest arxiu .hbm.xml**. El propi mecanisme de les anotacions ens estalviarà haver de fer-lo servir.

#### Canvis a l'hibernate.cfg.xml

Cal modificar la secció dels arxius de mapatge afegint a les darreres línies això:

```
    </session-factory>
    .....
        <mapping resource="tasks.hbm.xml"/>

    .....

    </session-factory>
```

D'aquesta forma li diem a l'hibernate on ha de buscar les referències per establir el mapatge entre entitats i taules de la base de dades.

En cas de fer servir anotacions, veurem que caldrà substituir el mapping resource per aquesta altra etiqueta. Però per ara no ho farem.

```
<!-- Mapeo DENTRO DE LA CLASE -->
<mapping class="com.iticbcn.hibernate.model.tasks"/>
```

#### Canvis a la classe d'aplicació

Abans de continuar val a dir que hibernate no ens crearà la base de dades, per tant l'haurem de crear nosaltres al SGDB (o bé utilitzar una base de dades existent).

Per fer la creació ens connectem a mariaDB i fem el "CREATE DATABASE tasks;"

Cal reflexar aquests canvis a l'hibernate.cfg.xml, a la cadena de connexió:

```
<property name="connection.url">jdbc:mariadb://localhost:3306/tasks</property>
```

Ara si, anem a la classe App i posem el següent codi, on instanciem un objecte de la classe tasques que volem persistir i fem el persist de l'objecte. Per fer-ho, com és obvi, cal haver obert la sessió i començat la transacció:

```
package com.iticbcn.hibernate;

import org.hibernate.SessionFactory;
import com.iticbcn.hibernate.model.tasks;

import org.hibernate.Session;

public class App 
{
    public static void main( String[] args )
    {
        SessionFactory sesion = HibernateUtil.getSessionFactory();

        Session session = sesion.openSession();

        session.beginTransaction();

        tasks t = new tasks("Donar la Benvinguda",1,true);

        session.persist(t);

 //commit y cierre de sesion

        session.getTransaction().commit();

        session.close();

    }
}

```

Per tal que tot funcioni caldrà fer el commit de la transacció i tancar la sessió. A partir d'aquí l'objecte quedarà persistit. Important: la sessió la tanquem un sol cop, és a dir, un cop haguem instanciat i persistit els diferents objectes ja podem tancar la sessió.

El resultat d'execució d'aquest codi serà semblant a aquest:

```
Hibernate: create table tasks (idTask integer not null auto_increment, descTask varchar(255), numHours integer, finalitzada bit, primary key (idTask)) engine=InnoDB
tasks [idTask=0, descTask=Donar la Benvinguda, numHours=1, finalitzada=true]
Hibernate: insert into tasks (descTask,finalitzada,numHours) values (?,?,?)
```

I ja per últim, comprovem que la taula ha estat creada fent un SHOW COLUMNS FROM tasks:

```
MariaDB [tasks]> SHOW COLUMNS FROM tasks;
+-------------+--------------+------+-----+---------+----------------+
| Field       | Type         | Null | Key | Default | Extra          |
+-------------+--------------+------+-----+---------+----------------+
| idTask      | int(11)      | NO   | PRI | NULL    | auto_increment |
| descTask    | varchar(255) | YES  |     | NULL    |                |
| numHours    | int(11)      | YES  |     | NULL    |                |
| finalitzada | bit(1)       | YES  |     | NULL    |                |
+-------------+--------------+------+-----+---------+----------------+
4 rows in set (0,001 sec)
```

A més de veure que el registre ha estat inserit fent SELECT:

```
MariaDB [tasks]> select * from tasks LIMIT 1;
+--------+--------------------+----------+-------------+
| idTask | descTask           | numHours | finalitzada |
+--------+--------------------+----------+-------------+
|      1 | Donar la benviguda |        2 |            |
+--------+--------------------+----------+-------------+
1 row in set (0,001 sec)
```

## Consultes d'objectes persistits

Veiem dues maneres de treballar amb objectes persistents:

### getReference

Amb getReference s'obté una referència a un objecte persistent donat el seu tipus i el seu identificador, sense carregar el seu estat des de la base de dades.

Posem per cas que volem recuperar la tasca amb id=2. El nostre main hauria de fer alguna cosa semblant a això:

```
        SessionFactory sesion = HibernateUtil.getSessionFactory();

        Session session = sesion.openSession();

        tasks t1 = new tasks();

        t1 = (tasks) session.getReference(tasks.class, "2");

        System.out.println(t1.toString());

        session.close();
```

El resultat d'executar aquest codi seria:

```
Hibernate: select t1_0.idTask,t1_0.descTask,t1_0.finalitzada,t1_0.numHours 
from tasks t1_0 where t1_0.idTask=?
tasks [idTask=2, descTask=Acomiadarse, numHours=1, finalitzada=true]
```

### find

El mètode find obté un objecte persistent a partir del seu tipus i id:

```
        SessionFactory sesion = HibernateUtil.getSessionFactory();

        Session session = sesion.openSession();

        tasks t1 = new tasks();

        t1 = session.find(tasks.class, "2");

        System.out.println(t1.toString());

        session.close();
```

El resultat d'executar l'anterior codi seria el següent:

```
Hibernate: select t1_0.idTask,t1_0.descTask,t1_0.finalitzada,t1_0.numHours 
from tasks t1_0 where t1_0.idTask=?
tasks [idTask=2, descTask=Acomiadarse, numHours=1, finalitzada=true]
```

PREGUNTA: Quina diferència hi ha entre els dos mètodes? És preferible utilitzar un o l'altre?


## Mètodes deprecats a la darrera versió d'hibernate

A Hibernate 6 els següents mètodes, presents a altres versions (i molt propis d'hibernate), han quedat deprecats i no es recomana el seu ús:

* save
* update
* saveOrUpdate

## Diferències JPA i Hibernate

JPA o Java Persistence API és una especificació de persistència de java, la [JSR-338](https://jcp.org/en/jsr/detail?id=338). Com especificació indicarà les anotacions que es poden utilitzar, de quina manera s'han de persistir els objectes, etc.

Hibernate és un framework que implementa aquesta especificació, tot i que aporta funcionalitats addicionals respecte a JPA. I això pot crear incompatibilitats i que el codi no sigui portable. De fet, les darreres versions d'hibernate tendeixen a convergir més amb l'especificació i això ha provocat que determinats mètodes i anotacions hagin quedat deprecats (com hem vist anteriorment). A més, pensem que JPA és utilitzat per Spring (un altre framework) en la forma de Spring JPA (com verurem a la UF4).

Una de les principals diferències la trobem en el fet que JPA treballa amb l'EntityManager en comptes de la SessionFactory com si ho fa Hibernate. 

## Exercicis

1. Què succeeix si després del .close() fiquem les següents línies?

```
        t1.setDescTask("No puc més");

        session.persist(t1);
```

En quin estat queda l'objecte t1? De quina forma o amb quin mètode aplicat a la sessió pot l'objecte t1 arribar a aquest estat?

2. Suposem que l'objecte t1 ha canviat el valor de la seva descripció (o de les hores si voleu) un cop la sessió ha quedat tancada. Quin codi cal afegir al main per tal que es persisteixin aquests canvis? Quins mètodes es poden utilitzar?