Operaciones básicas

Operaciones básicasUna parte esencial de utilizar JPA es saber utilizar las operaciones básicas, operaciones mediante las cuales es posible consultar, persistir, actualizar y eliminar entidades, de estas operaciones estaremos hablando hoy.

 

Gran parte de la funcionalidad de JPA es expuesta por medio de la Interface EntityManager, de la cual ya hemos hablado con anterioridad, y es por medio de esta interface, que es posible realizar las operaciones básicas. Las operaciones o métodos que exponen EntityManager son persist, merge, remove, find entre otras, que son sin duda las operaciones que más utilizaremos los proyectos.

En la sección anterior de este tutorial, hablamos de los estados de las entidades, las cuales será clave para entender cómo y cuándo deberemos utilizar dichas operaciones.

 

Sin más, las operaciones se describen a continuación:

Método Persist

Mediante esta operación es posible persistir en la base de datos una nueva (new) Entidad, la cual ha sido creada recientemente o persistir una Entidad que se encuentra en el Persistence Context (Atached).

Esta operación la debemos de utilizar cuando queremos persistir una Entidad que ha sido creada recientemente mediante el operador new, o cuando queremos actualizar una Entidad que fue cargada previamente al Persistence Context o dicho de otra manera, para actualizar una Entidad en estado atached.

Veamos un ejemplo de cómo persistiríamos una nueva Entidad:

 

package com.obb.jpa.jpaturorial.exercises;

import com.obb.jpa.jpaturorial.entity.Employee;
import com.obb.jpa.jpaturorial.entity.Status;
import com.obb.jpa.jpaturorial.util.EntityManagerUtil;
import java.util.Calendar;
import javax.persistence.EntityManager;

/**
 * @author Oscar Blancarte
 */
public class CreateEmployee {

    public static void main(String[] args) {
        //Create new EntityManager
        EntityManager manager = EntityManagerUtil.getEntityManager();

        //Open Trnsaction
        manager.getTransaction().begin();

        Employee employee = new Employee();
        employee.setName("Oscar Blancarte");
        employee.setRegistDate(Calendar.getInstance());
        employee.setSalary(1000);
        employee.setStatus(Status.ACTIVE);
        
        //Persist Employee
        manager.persist(employee);
       
        //Commit Transaction
        manager.getTransaction().commit();
    }
}

 

En las líneas 16 y 19 creamos el EntityManager y abrimos una nueva transacción, En las líneas 21 a 25, creamos un nuevo Empleado y establecemos sus propiedades, seguido utilizamos la instrucción manager.persist(employee)  para marcar la entidad para ser persistida, finalmente en la línea 31 cerramos la transacción. Observemos que tan solo es necesario pasar la Entidad como parámetro para que JPA realice la inserción.

 

Método Merge

La operación merge es utiliza para actualizar una entidad existente que no pertenece a un Contexto de persistencia. Esta operación la debemos utilizar cuando queremos actualizar una entidad que ya existe en la base de datos, pero por algún motivo, esta no está dentro del Contexto de Persistencia, este escenario se da cuando utilizamos DTO para viajar la información del FrontEnd al BackEnd, en donde convertimos el DTO a una Entidad y esta entidad ya existe en la base de datos. Veamos como utilizamos esta operación:

 

package com.obb.jpa.jpaturorial.exercises;

import com.obb.jpa.jpaturorial.entity.Employee;
import com.obb.jpa.jpaturorial.entity.Status;
import com.obb.jpa.jpaturorial.util.EntityManagerUtil;
import java.util.Calendar;
import javax.persistence.EntityManager;

/**
 * @author Oscar Blancarte
 */
public class UpdateEmployee {
    public static void main(String[] args) {
        //Create new EntityManager
        EntityManager manager = EntityManagerUtil.getEntityManager();
        
        //Query Employee by ID
        
        //Open Transaction
        manager.getTransaction().begin();
        
        //Set Employee Status
        Employee employee = new Employee();
        employee.setId(1L);
        employee.setName("Oscar Blancarte");
        employee.setRegistDate(Calendar.getInstance());
        employee.setSalary(1000);
        employee.setStatus(Status.INACTIVE);
        
        //Update Employee Status
        manager.merge(employee);
        
        //Commit changes
        manager.getTransaction().commit();
    }
}

 

Veamos que este ejemplo es prácticamente igual al ejemplo de la operación persist, sin embargo, existe una gran diferencia, en la línea 24 establecemos el ID de la entidad, lo que significa que cuando se realice el Merge, este se realice sobre el mismo registro. La segunda diferencia está en la línea 31, donde utilizamos la operación manager.merge(employee) .

 

Método Find

 

Esta operación es básica para buscar una Entidad solamente por su ID, mediante esta operación es posible recuperar la Entidad de la base de datos. Recordemos que una Entidad puede tener un ID de un solo campo o tener una llave compuesta, mediante @IdClass  y@EmbeddedId, cuando se trata de una llave simple, solo será necesario consultar la entidad por el valor de la llave primaria, sin embargo, cuando la llave es compuesta, el parámetro deberá ser del tipo de la llave primaria, es decir de la clase marcada como @IdClass  o @EmbeddedId . Veamos un ejemplo de cómo quedaría:

 

package com.obb.jpa.jpaturorial.exercises;

import com.obb.jpa.jpaturorial.entity.Employee;
import com.obb.jpa.jpaturorial.util.EntityManagerUtil;
import javax.persistence.EntityManager;

/**
 * @author Osccar Blancarte
 */
public class ReadEmployee {
    public static void main(String[] args) {
        //Create new EntityManager
        EntityManager manager = EntityManagerUtil.getEntityManager();
        
        //Query Employee by ID
        Employee employee = manager.find(Employee.class, 1);
        
        //Print name of Employee
        System.out.println("Employee name ==> " + employee.getName());
    }
}

 

Veamos que la operación find requiere dos parámetros, el primero es la clase de la entidad que esperamos buscar y el segundo valor es el ID. En este caso se trata de una llave simple, por lo que con mandar el valor 1 será suficiente, sin embargo, como mencione anteriormente, en caso se ser compuesta, deberemos mandar la clase que corresponde con la llave primaría.

Como resultado, la operación find retornara la Entidad con el ID = 1 con todas sus propiedades.

 

Método Remove:

 

La operación remove es muy simple, pues solo es requerido enviar la Entidad que se desea remover. La Entidad tendrá que estar dentro del contexto de persistencia para poder ser eliminada, de lo contrario nos arrojara una excepción. Veamos cómo utilizar esta operación:

 

package com.obb.jpa.jpaturorial.exercises;

import com.obb.jpa.jpaturorial.entity.Employee;
import com.obb.jpa.jpaturorial.util.EntityManagerUtil;
import javax.persistence.EntityManager;

/**
 * @author Oscar Blancarte
 */
public class DeleteEmployee {
    public static void main(String[] args) {
        //Create new EntityManager
        EntityManager manager = EntityManagerUtil.getEntityManager();
        
        //Query Employee by ID
        Employee employee = manager.find(Employee.class, 1L);
        
        //Open transaction
        manager.getTransaction().begin();
                
        //Delete Employee
        manager.remove(employee);
        
        //Commit transaction
        manager.getTransaction().commit();
    }
}

 

Lo primero que hacemos es consultar al Empleado mediante el la operación find, esto debidos a que la debemos de tener dentro del contexto de persistencia, seguido en la línea 22 ejecutamos la operación manager.remove(employee  lo cual provocara que la entidad sea eliminada de la base de datos y del contexto de persistencia.

 

Método Refresh:

Operación que permite actualizar la Entidad con la base de datos, tan solo es necesario mandar como parámetro la Entidad a actualizar, esto actualizará todos los atributos con los de la base de datos:

manager.refresh(employee);

No regresa nada, pues actualiza la misma entidad que se envió como parámetro.

 

Método Detach:

Operación que permite sacar una Entidad del Contexto de persistencia. Todo cambio realizado en la entidad será descartado al terminar la transacción.

manager.detach(employee);

La entidad queda en estado detached una vez ejecutada esta instrucción.

 

Método Clear:

Limpia el Contexto de Persistencia, por lo que todas las entidades pasarán al estado detached

Manager.clear();

Todos los cambios realizados en la transacción serán desechados.

 

Método Contains:

Operación que permite saber si una entidad se encuentra en el Contexto de persistencia. Se envía la Entidad a validar y retorna una booleano, indicando si está o no en el Contexto de Persistencia.

boolean exist = manager.contains(employee);

 

Existen muchas operaciones más que nos proporciona el EntityManager, pero estas las veremos gradualmente durante el desarrollo de este tutorial.

AnteriorÍndiceSiguiente

10 thoughts to “Operaciones básicas”

  1. En relación al método contains, que devuelve un booleano.
    ¿Sirve únicamente cuando no hemos agregado la entidad al archivo persistence.xml ó de alguna otra manera valida otros datos?

    1. No, lo que hace constains es determinar si la entidad se encuentra en el contexto de persistencia. ¿Que significa esto?, que el EntityManager lo esta actualmente administrando y esto ocurre cuando damos persist, update, merge o cualquier operación de búsqueda previa a llamar el método contains.

      Como nota, cualquier entidad que no sea agregada al archivo Persistence.xml o que sea administrada por JPA no puede ser llamada entidad, por lo tanto NUNCA estará en el contexto de peristencia, por ende, nunca obtendrás un true de contains.

      Espero que esto resuelva tu duda.
      saludos.

  2. El método flush, según la documentación oficial, debería hacer algo así como un pre-persist del o de los objetos que estén el el contexto de persistencia. No obstante tengo un caso donde intento persistir/rollback de varios objetos en una misma transacción utilizando UserTransaction; la cuestión es que haciendo pruebas provocando un error de base de datos en una de las entidades a persistir, al hacer rollback de la transacción se queda una parte de los objetos persistidos en la base de datos. En general es que por razones ajenas, se necesitan insertar varias entidades a la base de datos, y aunque están relacionadas entre si, se deben realizar en operaciones separadas.

    https://stackoverflow.com/questions/54180622/jpa-nested-transactions-all-commit-rollback-after-runtime-exception

    1. Hola Luis, cuando utilizas UserTransaction el programador es el responsable de controlar las transacciones, en tal caso, tendrías que revisar si no estás haciendo commit sin querer. Cuando utilizamos UserTransaction es común crear dos o más entityManager, lo que provoca que tengamos dos persistence context, eso puedo ocasionar que uno haga commit y el otro haga rollback, asegúrate de usar siempre la misma instancia del EntityManager o utilizar el método joinTransaction(), para segurar que todo ocurra en la misma transacción.

      1. Hola Oscar, ante todo gracias por la rápida respuesta. La cuestión es que estoy utilizando un solo entity manager para todo, y es curioso porque hice un prototipo de pruebas para emular lo que quería y me funcionó perfectamente como transacción, y cuando lo hacía fallar en efecto hacía rollback como se espera. Cuando fui a implementar lo mismo pero con las clases de un proyecto real, pues me sucede lo que te comento. Piensa que utilizo un solo entityManager por cuestiones de rendimiento y consumo de conexiones a la BD, y hasta el momento funciona bien, solo tengo el problema de la transaccionalidad que es como si estuviera haciendo, como dices, dos contextos cuando debería ir todo por uno solo. Podrías aclararme un poco el uso del driver, sobre qué clase debería utilizar oracle.jdbc.pool.OracleDataSource o más directamente oracle.jdbc.xa.OracleXADataSource, aunque entiendo que la segunda es una subclase de la primera. Gracias por adelantado

        1. Los drivers XA son para transacciones distribuidas, es decir, cuando transaccionamos con más de una base de de datos, ha esto se le conoce como 2 Phase commit o Commit de dos fases, puedes leer más sobre esto en mi articulo. El otro driver (oracle.jdbc.pool.OracleDataSource) no me suena tanto, tendrías que revisar la documentación oficial para entender para que se utiliza.

      1. Me ocurre exactamente igual que a Berta, al introducir los datos en la base de datos, si ya existian datos eran eliminados y solo quedaba el ingresado, nuevamente al hacer otra inserción el dato nuevo reemplaza al anterior en la base de datos; en mi caso pasa si ejecuto una vez la aplicación e ingreso los datos uno a uno o si ejecuto la aplicación luego de cada ingreso.
        Agradezco la ayuda!

        1. Hola, revisa dentro del archivo persistence.xml el valor de la propiedad javax.persistence.schema-generation.database.action, seguramente está en drop-and-create

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *