Estrategias de carga con @Basic

Tutorial de JPA @Basic@Basic es una anotación que nos permite controlar el momento en que una propiedad es cargada desde la base de datos, evitando que traer valores que no son necesario al momento de cargar el objeto. Esta anotación es utilizada generalmente para anotar objetos pesados, como una imagen o un archivo binario.

@Basic

En JPA existe dos conceptos que son claves para entender cómo es que JPA carga los objetos desde la base de datos y estos son claves para mejorar el rendimiento de la aplicación, estos conceptos se explican a continuación:

  • Lazy loading (Carga demorada): Los objetos de carga demorada no serán cargados desde la base de datos cuando el objeto sea creado, pero será cargado en cuanto se acceda a la propiedad. De esta manera JPA identifica cuando la propiedad es accedida por primera vez para cargar el valor desde la base de datos.
    • @Basic( fetch = FetchType.LAZY )
  • Eager loading (Carga ansiosa o temprana): Este es la utilizada por default para la mayoria de las propiedades en JPA, a excepción de las colecciones las cuales las analizaremos mas adelante.
    • @Basic( fetch = FetchType.EAGER )

Lazy loading se logra mediante la utilización del patrón de diseño Proxy, el cual también explico con más detalle en mi libro.

La anotación @Basic define además la propiedad optional, la cual es de tipo booleano, si se le indica true, se decimos a JPA que esta propiedad es opcional y en ella puede haber un valor Null, en caso se ser false, le indicamos que la propiedad siempre deberá tener valor. Esta propiedad es más que nada para ayudar a JPA a optimizar los query para obtener los valores. Pero tendrá que corresponder con la realidad, ya que en caso de marcar que no es opcional y este valor es null en la base de datos JPA marca error.

NOTA: optional  es diferente  de nullable  de @Column, pues nullable sirve para definir la estructura de la columna y optional son sugerencias a JPA para optimizar los querys. Nunca debemos de confundir eso.

Un punto importante es que @Basic se puede emplear prácticamente para cualquier como tipos primitivos, clases wrapper, Calendar, enums, Time, Date, Timestamp. byte[], char[], clases que implementan java.lang.Serializable, etc.

Ya con toda la teoría, pasaremos a ponerla en práctica. Retómenos la clase Employee que hemos utilizando en todos el tutorial para agregar una nueva propiedad llamada photo, esta será de tipo bute[] y guardara el binario de la foto del empleado. La foto al ser un campo pesado lo marcaremos como LAZY, para evitar que se cargue al crear el objeto y solo cuando sea necesario se cargue. Por otra parte, la foto del empleado no es obligatoria por lo que definiremos la propiedad optional = true.  Veamos cómo quedaría:

package com.obb.jpa.jpaturorial.entity;

import java.util.Calendar;
import java.util.Objects;
import javax.persistence.*;

/**
 * @author Oscar Blancarte
 */
@Entity
@Table(
    name = "EMPLOYEES" , 
    schema = "jpatutorial", 
    indexes = {@Index(name = "name_index", columnList = "name",unique = true)}
)
public class Employee {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY, generator = "EmployeeTable")
    @Column(name = "ID")
    private Long id;
    
    @Column(name = "NAME", nullable = false, length = 150)
    private String name; 
    
    @Column(name = "SALARY", nullable = false, scale = 2)
    private double salary;
    
    @Column(name = "REGIST_DATE", updatable = false, nullable = false)
    @Temporal(TemporalType.DATE)
    private Calendar registDate;
    
    @Column(name="STATUS", nullable = false, length = 8 )
    @Enumerated(value = EnumType.STRING)
    private Status status;
    
    @Column(name = "PHOTO" ,nullable = true)
    @Basic(optional = false, fetch = FetchType.EAGER)
    @Lob()
    private byte[] photo;
    
    /**
     * GETs and SETs
     */
}

Veamos que la anotación @Column se define para indicar el nombre de la columna de la base de datos y está definida la propiedad nullable=true debido a que la foto no es obligatoria. Recordemos la diferencia entre nullable & optional que ya analizamos.

NOTA: En la siguiente sección describiremos la anotación @Lob, por lo pronto solo dejémosla pasar por alto.

Tambíen los quiero invitar a ver mi curso de JPA, donde explico todos estos temas aplicados con API REST, https://codmind.com/courses/jpa

👉👉 Los invito a mi Curso de Mastering JPA, donde habla de todos estos temas y crearemos un API REST para probar todos los conceptos de persistencia.
👈👈

Finalmente, y tras ejecutar la aplicación para creer las tablas, veremos que la tabla queda de la siguiente manera:

@Basic

La columna PHOTO se ha creado de tipo Longblob debido a que la propiedad es de tipo byte[] y puede ser de gran tamaño.

NOTA: Este artículo es solo una sección del Tutorial de JPA, para ver el contenido completo de este tutorial regresa al Índice en el botón de abajo.

AnteriorÍndiceSiguiente

2 thoughts to “Estrategias de carga con @Basic”

  1. Buenas Oscar.
    De nuevo, enhorabuena por tu blog, y toda la info de JPA. Yo lo que he observado en los proyectos en los que he utilizado JPA en la capa de persistencia, es que hay que tener cuidado cuando utilizamos LAZY o EAGER y estamos debugeando, de no despistarnos al ver que normalmente nos llega a null o vacío un campo que tenemos definido como lazy y luego al finalizar de debugear y ejecutar la aplicación, vemos que efectivamente no es ni null ni vacío, sino que al ser lazy nos llega a posteriori.

    Saludos.

    1. Hola Silvia, esa es una buena observación, cuando utilizamos LAZY, JPA en realidad lo que hace es agregar un Proxy, este proxy lo que hace es que no contiene al valor como tal, sino que esta implementado para que al momento de obtener los datos es los consulte en la base de datos. Cuando debugeamos normalmente estas herramientas introspecta (Reflection) los objetos para darnos los datos que tiene, de esta forma puede que el valor sea null por que el valor no es leído por lo métodos de acceso get, de esta forma, el proxy no se entera y no carga el valor al momento de verlo en el debuger.

      Otro problema habitual es leer el valor fuera de la capa de servicios, por ejemplo, si pasas la Entity de un EJB a un Controller de JSF e intentas cargar un atributo que es LAZY y no lo habías cargado antes, entonces te marcara error, porque ya no estarás dentro del contexto de persistencia.

Deja un comentario

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