Entidades

En esta sección voy a crear una Entidad en CUBA Studio con algunas entidades asociadas y sus correspondientes pantallas.

Vamos a guiarnos en un modelo desarrollado bien en Toad Data Modeler Freeware, bien con SQL Database Modeler.

Las dos opciones nos permiten hacer ingeniería inversa de la BD, aunque Toad necesita ser instalado y SqlDBM se usa online.

En este caso voy a usar SqlDBM. Se puede usar un enlace de solo lectura para que no editemos los diagramas por error. En caso de una BD nueva, he usado Toad pero con un modelo lógico, ya que no son necesarias las claves al crearlas el ORM de CUBA.

Voy a comenzar con la Entidad Comunero, para ello me fijo en la entidad importada en SqlDBM COMUNEROS

En este caso, esta entidad es de SICRE, y usaba un tipo de datos T_Si_No que realmente era una lista de valores S y N. Pero SqlDBM no lo importa bien y lo pone como dbo, yo los he cambiado a boolean aunque SQL Server no lo tiene, y el mas parecido es bit.

Para los demás tipos de datos, vamos a ir viendo como convertirlos a los de CUBA a medida que nos vayan saliendo.

En este apartado voy a seguir los pasos para crear un Enum o Enumeración. En el cas de SICRE, se usan varios, en el caso de la Entidad Comunero tenemos por ejemplo Sexo tiene los valores M y F, Masculino y Femenino.

En este apartado voy a seguir los pasos para crear un Enum o Enumeración. En el cas de SICRE, se usan varios, en el caso de la Entidad Comunero tenemos por ejemplo Sexo tiene los valores M y F, Masculino y Femenino.

  1. Lo primero es crear la entidad pulsando en el árbol en Data Model/New/Enum.
  2. Elegimos Sexo como nombre y String como tipo Id Type
  3. En el archivo Sexo.java nos tiene que quedar:
public enum Sexo implements EnumClass<String> {
    M("M"),
    F("F");
 
    private String id;
 
    Sexo(String value) {
        this.id = value;
    }
 
    public String getId() {
        return id;
    }
 
    @Nullable
    public static Sexo fromId(String id) {
        for (Sexo at : Sexo.values()) {
            if (at.getId().equals(id)) {
                return at;
            }
        }
        return null;
    }

Además, en el archivo messages.properties ponemos el texto que queremos que aparezca:

Sexo=Sexo
Sexo.M=Masculino
Sexo.F=Femenino

Por defecto CUBA genera un tipo de dato varchar(50) para albergar los valores de un enum en la BD, sin embargo parece que podemos forzar el tipo de dato SQL que se genera por el ORM. Podemos hacerlo en el apartado Column Definition, por ejemplo podemos poner char(1) para que se use este tipo de dato en los enums de un solo carácter. Hay que comprobarlo.

Voy a poner una serie de pasos para hacer una Entidad:

  1. Lo primero es crear la entidad pulsando en el árbol en Data Model/New/Entity.
  2. Como el diseño era muy antiguo, la tabla estaba en plural, por lo que la entidad la pondré en singular Comunero. Los demás parámetros los dejamos como están. Si queremos que en lugar del directorio ..Entity, cada entidad esté en su propio subdirectorio, nombramos el paquete con el nombre de la clase. Otro enfoque podría ser crear un paquete por cada modelo de BD, aunque una tabla puede aparecer en mas de un modelo y habría que decidir en qué paquete estará.
  3. Para facilitar la migración de versiones anteriores, vamos a poner el mismo nombre a las tablas que en SICRE, por ejemplo para la entidad Comunero, la tabla será COMUNEROS.
  4. También para facilitar la migración desde versiones anteriores de SICRE, pondremos las columnas con los mismos nombres que en la BD antigua. Por ejemplo el atributo numeroRecibo generará el nombre de columna NUMERO_RECIBO, u nosotros lo cambiamos a NUMERORECIBO.
  5. El primer atributo que se crea siempre es ID y se nos propone el tipo UUID. Este atributo será también la llava primaria. Esto plantea ventajas al no depender la clave primaria de ningún valor usado, por ejemplo el DNI, ya que podemos cambiar el DNI sin tener que cambiarlo en todas las ocurrencias en las que aparezca por ejemplo en llaves foráneas. El enfoque de usar llaves formadas por atributos normales nos permite consultar la BD desde SQL de forma mas directa. De cualquier forma, mediante las propias vistas de CUBA o con consultas y vistas un poco modificadas conseguimos el mismo resultado.
  6. Vamos añadiendo los atributos según los que aparecen en el diagrama. El nombre debe estar escrito en camelCase y para el nombre de la columna colocamos el mismos que en el diagrama. Not Null es Mandatory y las claves se marcan como Unique. Para el caso de los valores char(n), usamos la restricción @Length con el valor n como mínimo y máximo.
  7. Como el atributo ID es el que se usa como clave, en el caso de una BD heredada, las antiguas claves, ahora se ponen como anotaciones unique con lo que se genera un índice para ese campo en lugar de una clave primaria.
  8. En el caso de llaves compuestas como es el caso de (SERIE, NUMERORECIBO), si ponemos unique en cada check de cada atributo lo que conseguiremos son dos índices, uno para cada campo:
    CREATE UNIQUE INDEX IDX_RECIBOS_UNIQ_NUMERORECIBO ON RECIBOS (NUMERORECIBO) ^
    CREATE UNIQUE INDEX IDX_RECIBOS_UNIQ ON RECIBOS (SERIE, NUMERORECIBO) ^

    Para conseguir un índice sobre los dos campos, deberemos usar anotaciones sobre las tablas (en versiones anteriores de STUDIO se hacía desde el entity designer). Por ejemplo la tabla RECIBOS correspondiente a la entidad Recibo originalmente está definida como:

    @Table(name = "RECIBOS")
    @Entity(name = "pruebawiki_Recibo")

    y tenemos que modificar el código para que quede así:

    @Table(name = "RECIBOS", uniqueConstraints = {
            @UniqueConstraint(name = "IDX_RECIBOS_UNIQ", columnNames = {"SERIE", "NUMERORECIBO"})
    })
    @Entity(name = "pruebawiki_Recibo")

    además se generará el índice:

    CREATE UNIQUE INDEX IDX_RECIBOS_UNIQ_SERIE ON RECIBOS (SERIE) ^

    Por supuesto deberemos desmarcar unique para que no se generen los anteriores índices.

  9. ACTUALIZACIÓN. A partir de la versión 10.1 de CubaStudio, existe una vista para índices similar a la anterior.
  10. Si queremos forzar el tipo de dato SQL que se genera por el ORM, podemos hacerlo en el apartado Column Definition, por ejemplo podemos poner numeric(10, 2) para que se use este tipo de dato en lugar de decimal(10, 2) que es el que se genera cuando se unaa un BigDecimal.
  11. Equivalencia de los tipos de datos en SICRE (ver DMBS Types):
    1. varchar → String
    2. char → String
    3. numeric(n,m) → BigDecimal(n.m)
    4. image → byte[]
    5. datetime → time
    6. datetime → date
    7. datetime → datetime

Básicamente hay dos tipos de relaciones:

  • ASSOCIATION. Asociación, en este caso las dos entidades pueden existir de manera independiente.
  • COMPOSITION. Composición, este es el caso de las relaciones maestro-detalle. Por ejemplo un pedido y sus líneas, las líneas no pueden existir sin el pedido al que pertenecen.

Dependiendo de la cardinalidad podemos tener los siguientes casos:

  • Ítem de lista desordenada

Un ejemplo lo podemos ver en la guía Data Modelling: Composition.

Ejemplo de Lookup

Este es el caso de la relación entre RECIBOS y COMUNEROS, en el que un Recibo tiene que tener un Comunero.

Podemos ver las diferentes notaciones entre los diagramas de Toad (Crow's foot) a la izquierda, y los de SqlDBM a la derecha. Esta situación un ejemplo claro de lookup, en el que se elije un Comunero par un Recibo. (Realmente por pantalla no se debería poder cambiar el Comunero)

En este caso, en la entidad Recibo añadimos el atributo socio:

  • El tipo de atributo es ASSOCIATION.
  • El tipo es Comunero.
  • La cardinalidad es MANY_TO_ONE, ya que si nos fijamos en los diagramas anteriores, RECIBOS está en la parte muchos de la relación, y COMUNEROS en la parte uno.
  • El tipo de lookup puede ser:
    • DROPDOWN, para casos con pocos valores en los que sólo se despliega una lista.
    • SCREEN, para casos con muchos valores, como es este, en el que se abrirá una ventana para seleccionar un elemento.
  • En lookup actions podemos marcar:
    • lookup, para que nos muestre el botón de desplegar.
    • clear, para que muestre el botón de borrar lo introducido.
    • open, para que nos muestre el botón de abrir.
  • Por último, aparece el campo SOCIO_ID que es el campo que contendrá el valor del ID del Comunero que actúa como Socio. En el modelo original de SICRE, al ser NUMEROSOCIO la clave primaria, el campo equivalente sería NUMEROSOCIO. Este enfoque es más rápido a la hora de hacer búsquedas, así que se podría guardar el campo también en la tabla, aunque desde CUBA se hacen las operaciones pertinentes para usar el ID.

Ejemplo de Maestro/Detalle

Este es el caso de la relación entre RECIBOS y ANEXORECIBO, en el que un Recibo puede tener varios Anexos.

Podemos ver las diferentes notaciones entre los diagramas de Toad (Crow's foot) a la izquierda, y los de SqlDBM a la derecha. Esta situación un ejemplo claro de master/detail, en el que se elije un Recibo puede tener varios Anexos. Además, un Anexo no puede existir sin un Recibo.

En este caso, en la entidad Recibo añadimos el atributo anexos:

  • El tipo de atributo es COMPOSITION.
  • El tipo es AnexoRecibo.
  • La cardinalidad es ONE_TO_MANY, ya que si nos fijamos en los diagramas anteriores, RECIBOS está en la parte uno de la relación, y ANEXORECIBO en la parte muchos.
  • El tipo de borrado On delete es como se definió anteriormente.
  • Podemos definir también el borrado inverso.
  • Elegimos el tipo de estructura Java que va a contener los elementos, puede ser Set, List o Collection.
  • En Mapped by elegimos create inverse attribute…, lo que nos crea el atributo RECIBO_ID en la entidad AnexoRecibo con lo que podemos recorrer la relación en las dos direcciones. En el modelo original de SICRE, en ANEXORCIBO existía una llave foránea formada por (SERIE, NUMERORECIBO), ahora sólo necesitamos el ID del Recibo. Además, el ORM nos cargará los Anexos de cada Recibo, disponibles en la lista anexos''.