Mapeo de tablas con @Table

Tutorial de JPA @TableEn la sección hablaremos de la anotación @Table  y su importancia a la hora de definir entidades. La anotación @Table es utilizada para indicarle a JPA contra que tabla debe de mapear una entidad, de esta manera cuando se realice una persistencia, borrado o select de la entidad, JPA sabrá contra que tabla de la base de datos deberá interactuar.

Anotación @Table

Como comenté, esta anotación se utiliza para indicar la tabla contra la que mapea la entidad, pero también tiene otras propiedades interesantes como las que se muestra a continuación:

  • name: se utiliza para poner el nombre real de la tabla en la base de datos, es recomendable que el nombre sea exacto respetando mayúsculas y minúsculas, sobre todo cuando trabajamos en Linux.
  • schema: se utiliza para indicar el schema en el que se encuentra la tabla. Esta propiedad por lo general no es necesaria, a menos que la tabla se encuentre en un schema diferente al que utilizamos para logeamos.
  • Indexes: JPA permite indicar los índex que tiene nuestra tabla, esta opción toma relevancia cuando indicamos que JPA cree las tablas por nosotros (más adelante veremos esta característica).

Veamos cómo quedaría @Table en la entidad Employee que revisamos en la unidad pasada:

package com.obb.jpa.jpaturorial.entity;

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

/**
 * @author Oscar Blancarte
 */
@Entity
@Table(
    name = "EMPLOYEES" , 
    schema = "jpatutorial", 
    indexes = {@Index(name = "name_index", columnList = "name",unique = true)}
)
public class Employee {
    private Long id;
    private String name; 

    /**
     * GETs and SETs
     */
}

Observemos que hemos definido que la clase Employee mape contra la tabla EMPLOYEES, le decimos que la tabla está en el schema jpatutorial y que tiene un index llamado name_index para ordenar el nombre del empleado. En el caso del index para el nombre del empleado, estamos diciendo que el nombre deberá ser único

NOTA: La notación @Table no es obligatoria, pero el hecho de no ponerla supone que JPA determine que la tabla se llama igual que la clase y la buscara en el schema en que estas logeado.

Auto generación de schemas

Una de las grandes ventajas de JPA es que puede crear todos los objetos de la base de datos como Tablas y Secuencias de forma automática por medio de lo metadatos. Este comportamiento es definido en el archivo persistence.xml, regresemos a este archivo y veremos que tiene una propiedad llamada Table Generation Strategy la cual tiene los siguiente posibles valores:

  • Create: Le indicamos a JPA que si un objeto no existe lo cree, pero si ya existe ese no será creado ni actualizado. Un detalle a tomar en cuenta es que si a una entidad de le agregamos un campo nuevo y su tabla ya existe, este campo nuevo no se creara, por lo que tendremos que actualizar manualmente la tabla o borrarla para que la cree de nuevo al instanciar el EntityManager.
  • Drop and Create: Esta estrategia borra todos los objetos para volverlos a crear, esta estrategia nos garantiza que todos los objetos de la base de datos estén actualizados con las entidades. PELIGRO: Esta estrategia es muy peligrosa, ya que nos borrara toda la información que tengamos en la base de datos y será imposible recuperarla, lo cual sería fatal si lo ejecutamos en ambiente productivo.
  • None: Con esta opción le decimos a JPA que no haga nada, es decir que no cree ni borre nada. Esta opción es la mejor cuando tenemos ya tenemos todo el modelo de base de datos desarrollado en la base de datos. O cuando nos conectamos a un modelo ya existente.

Yo te sugiero que inicies usando la estrategia Create para así no preocuparte por la creación de los objetos, por otra parte, mi consejo es que nunca uses Drop and create porque es demasiado riesgoso. En la sección siguiente veremos en acción esta propiedad ya que por el momento la entidad Employee no está terminado para hacer una prueba.

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.
👈👈

Retomando la propiedad index de @Table, esta propiedad solo sirve para la creación de la tabla y no tiene ningún funcionamiento en tiempo de ejecución, por lo que si tu estas trabajando con la estrategia None, entonces no tiene caso definir esta propiedad.

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

21 thoughts to “Mapeo de tablas con @Table”

  1. Estimado OScar muy buenos dias, muy intersante el blog, le comento que soy nuevo en estos de java y me esta sirviendo mucho la inforamción publicada, pero tengo un problema con la creacion de las tablas en la base, todo lo crea en minusculas y el orden de los campos varia con respecto a lo definido en la clase, necesito crear las tablas con el nombre “Empleado” y la crea como empleado o “DocumentosGenerales” como documentosgenerales y estoy trancado con este tema, como podria ayudar con este tema, gracias de antemano

    1. Hola Cristina, por lo que me cuentas, seguramente estas trabajando en Linux y probablemente utilizas MySQL como base de datos.

      Lo que te puedo recomendar, es utiliza siempre la anotación @Table(name=”“) en todas tus entidades, con la intención de forzar el nombre. Si esto no funciona, tiene que ver la instalación de la base de datos, pues algunas veces se instala para no ser sensible a Mayúsculas-Minúsculas, lo que hace que haga un Upper o Lower case de los nombre de los objetos.

      Finalmente, sería bueno saber que OS y base de datos esta utilizando, así como la implementación de JPA que estas utilizando, pues cada implementación funciona ligeramente diferente a las demas.

      1. Gracias por la pronta respuesta Oscar, bueno estoy trabjando con la PostgreQL 9.6 en windows 7 y la base me acepta para los nombres mayusculas y minusculas, estoy en un proyecto maven con spring boot y mi archivo de hibernateproperties:

        # ——————————
        # Spring Data JPA CONFIGURATION
        # ——————————
        hibernate.show_sql=true
        hibernate.format_sql=true
        hibernate.hbm2ddl.auto=create-drop
        hibernate.dialect =org.hibernate.dialect.PostgreSQLDialect

        1. Hola Cristian,

          Lo que me comentas me paso alguna vez y no recuerdo bien la solución que aplique, pero estoy casi seguro que fue debido a una configuración de la base de datos, si en tu caso se presenta incluso con una configuración que soporta Camel Case, entonces solo quedaría revisar la documentación de Hibernate para ver que propiedad pues aplicar para solucionar el problema. De entrada no se me ocurre más que eso.

          saludos.

  2. Muy buen Blog Oscar felicidades. Me ha servido mucho tu tutorial de JPA para reforzar el conocimiento que ya tenia del mismo.

    Gracias y saludos!

  3. Hola. Intento hacer una práctica como la tuya pero me falla. A ver, uso NetBeans 8.2, Glassfish 5 y Java DB (Derby) incluída en NetBeans. Lo que quería cambiar es un ejemplo de aplicación Web con JPA. A tal fin, he definido un formulario JSP que pide los datos de una factura y su cliente. Éste le pasa la info. a un Servlet que es el que graba los datos en la B/D. Al servlet le inyecto el EntityManager y todo va bien hasta que intento grabar. Si utilizo Transacciones (con begin y commit) me falla porque el servidor dice que son automáticas (JTA), como efectivamente pone en el persistence.xml. Si las quito, se queja porque faltan. Lo último que se me ocurrió es crear un método aparte del doPost() del servlet donde hacía la grabación (ya lo haré más adelante en otra clase) y dicho método (que recibe losl objetos creados en doPost con los getParameter(), lo he anotado con @TransactionAttribute(TransactionAttributeType.SUPPORT) -o REQUIRES_NEW, da igual…-. En cualquier caso sigue fallando con un mensaje así: javax.persistence.TransactionRequiredException. ¿Alguna luz que me guíe? Muchas gracias Óscar.

      1. Tengo estas líneas iniciales en el archivo de persistencia:

        jdbc/ventasdbp

        Ayer a última hora conseguí que me funcionara, pero es raro. Tuve que ponerle al Servlet “@Transactional” encima del “@WebServlet”. Al final, puse el método persist en otra clase, un CDI Bean, antes de intentarlo con EJBs, que era la segunda opción si me fallaba esta. Yo pensaba que la anotación @Transactional no tenía que ponerse en el Servlet (más bien en el CDI Bean) pero debe ser automática esa gestión de transacciones en los CDI. Probé de todo en todas partes hasta que al final funcionó y creó ambas tablas. Muchas gracias por tu ayuda y por tu excelente blog.

        1. Quería decir (se copió mal) que el persistence.xml empieza así:
          (persistence-unit name=”JPAVentasApPU” transaction-type=”JTA”)
          (jta-data-source)jdbc/ventasdbp(/jta-data-source)
          (sustituyo los signos mayor/menor por paréntesis por fallos en la transcripción al copiarlo aquí)

        2. Hola Pedro,
          Los Servlets por default no son transaccionales, por tal motivo te falla al momento de persistir, sin embargo, cuando lo anotas con @Transactional, lo que le dices al contenedor es que habilite la transaccionalidad. Por otra parte, los @EJB si son transaccionales por default, por lo que allí no es necesario más que anotarlos con @EJB para que el contenedor sepa que debe habilitar la transaccionalidad.

          Mi consejo es que uses el Servlet solo para recibir los datos, pero todas las operaciones de negocio las delegues a un EJB y desde allí realizas todas las operaciones de insert,update,delete,select.

          saludos,

          1. Sí, Óscar, al final hice “casi” lo que dices. La lógica de negocio, el DAO o como quieras llamarlo, lo desarrollé en una clase aparte. En lugar de EJB, me decanté por un CDI Bean, que son parecidos, pero más ligeros según entiendo…
            Me ha gustado mucho tu tutorial, así que seguiré consultando otros que hagas y así ir progresando.
            Un saludo y muchas gracias.

  4. Buenas tardes,

    Estoy intentando crear una API REST con spring boot y mysql, realizó todo el proceso, creación de la entidad, la clase REST y la configuración del archivo application.yml. Ejecuto la aplicación, no genera error pero cuando actualizo en mysql para verificar que la tabla se haya creado, no me aparece ningún registro, es decir, la tabla no se crea. Qué puede estar faltando? ya que está todo y no falla al ejecutar?

    1. Hola Carlos, eso se debe a que debes de indicarle en el archivo persistence.xml que cree las tablas al iniciar, intenta agregando la propiedad < property name="javax.persistence.schema-generation.database.action" value="drop-and-create" / > en la sección de propiedades de tu archivo.

  5. Estimado Oscar:
    Tengo una consulta. Tengo un motor de datos posgreSql y guardo archivos PDF, imágenes en un campo OID de posgre.

    cuando mapeo la Entity Adjunto, el campo OID lo mapeo de la siguente forma:

    @Lob
    @Basic(fetch = FetchType.LAZY)
    @Column(name = “contenido”,columnDefinition = “OID”)
    private byte[] contenido;

    cuando escribo en la Tabla adjunto usando usa el set del campo y todo bien, pero cuando quiero recuperar los datos de este campo contenido
    el getContenido() se cae porque JPA tontamente en su código interno asume que el campo OID de posgre es un Long y no se me ocurre alguna forma para que JPA no asuma el dato como Long sino como byte[], si en columDefinition coloco byte[] se cae igual, ya no sé qué hacer.
    por favor si me puedes ayudar, te juro que si me solucionas te compro la suscripción del año, completo, jejejeje
    por favor Oscar ayúdame, estoy usando eclipseLink (el campo no es id)

    1. Hola Ricardo, yo no he trabajado antes con columnas de tipo OID, pero lo que veo en la documentación es que, el tipo OID guarda valores númericos autoincrementantes, lo cual sería un tipo incorrecto por lo que buscas lograr. Yo lo que haría en tu lugar, es utilizar el tipo bytea, que según la documentación de postgres, es el tipo de dato para valores binarios. Intenta realizar ese ajuste, y me cuentas como te fue.

Deja un comentario

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