viernes, 28 de noviembre de 2014

Genexus y nulos

Este análisis se centra en como definir nulos en bases de conocimiento Genexus pero es extrapolable a cualquier modelo de datos (RDBMS, SQL, NoSQL).


¿Qué es un NULL?
En Genexus estamos acostumbrados a que es algo parecido a un Cero o a un String vacío según el tipo de datos, ya que Genexus trataba de ocultarnos los nulos utilizando nullvalues de esos tipos. Más adelante el concepto de nulo se desdobló en 2 conceptos: el NULL y el EMPTY que viene a tomar el lugar del nullvalue cuyo uso es preferible evitar por lo confuso que resulta su nombre.

Entonces un NULL es un valor indefinido (información inexistente o faltante) y tiene mucho sentido en las bases de datos relacionales cuando una relación es opcional. Ej. una Factura puede o no estar asociada a Orden de Compra.

Como ejemplo de lo indefinido que es un valor NULL, algunos RDBMS ordenan los nulos al principio (MSSQL y MySQL) y otros al final (Oracle, PostgreSQL).
Lo cierto es que ambos están correctos, porque un Nulo es indefinido por lo tanto no es ni menor ni mayor que otros valores, por eso algunos DBMS agregan cláusulas NULLS FIRST y NULLS LAST para controlar donde queremos que nos ordenen los nulos.


¿Cuando tiene sentido usar Nulos?

En mi experiencia, en un modelo de datos los lugares donde tiene sentido la utilización de Nulos son los siguientes:
  • Claves Foráneas opcionales (FK). Ej: Una Factura puede tener nulo en su atributo Orden de Compra, ya que es opcional.>
  • Fechas opcionales. Ej: Fecha de cobrada una factura, mientras la factura no esté cobrada el valor es indefinido.
  • Textos o Blobs opcionales. Ej. Una descripción vacía.

¿Qué significa Empty as Null?

Esto es una propiedad que Genexus usa en los atributos para controlar si querémos que un valor vacío se almacene como NULL. Según lo expresado antes, solo algunos tipos de atributo deberían tener la propiedad Empty as NULL = Yes.


¿Y la columna Nullable en la estructura de las transacciones?

Define si el atributo admite Nulos en esa transacción. No es lo mismo que Empy as Null pero ambos juegan juntos para dar el comportamiento final.
Ej. El atributo Orden de Compra tiene Empy as null = Yes porque es clave. A su vez, es opcional en la transacción de Facturas, pero obligatorio en la transacción de Remitos.
Entonces el mismo atributo va a llevar Nullable = Yes en Facturas y Nullable = False en Remitos. Es decir, el atributo puede guardar como nulo, pero en la transacción de Remitos no admite Nulos.


Voy entendiendo la idea pero me gustaría algo más concreto

Ahí van mis sugerencias. En un modelo Genexus (extrapolable a otros modelos de datos), tengo que definir los atributos de esta forma:


Tipo de atributoEmpty as nullNullable
Identificador/Clave no importa de que tipo de datos YES YES - solo si es opcional
Fecha, Texto, Blob YES YES - solo si es opcional
Cantidad, Importe, Dimensión, Booleano, Flag NO NO


¿Para qué me sirve todo esto? ¿Por qué no defino todo nullable o todo no nullable?

Las ventajas de usar valores Nulos ya fueron explicadas, nos da una expresividad mayor, ¿Para qué voy a guardar una fecha 01/01/0001 o 31/12/1753? Es mucho mejor gurdar un NULL que deja mucho más claro que el valor está indefinido.
Otro ejemplo son los DBMS que no aceptan textos nulos, por ejemplo un VarChar en Oracle se debe guardar un nulo o al menos un espacio, pero no acepta textos vacíos.

Entonces: ¿Por qué no admitir nulos en todos lados?
La respuesta a esta pregunta tiene 2 puntas:
  • Integridad en las FK: Si yo definí que los Remitos siempre tienen que tener asociada una Orden de Compra, no quiero que se pueda agregar un registro sin Orden de Compra, entonces en ese caso defino que no puede ser Nulo. Esto es a nivel de la base de datos, pero además Genexus utiliza esta información para validar en el Form que el usuario ingrese una Orden de Compra y de lo contrario no lo deja avanzar.
  • Las operaciones aritméticas con nulos están indefinidas. Por lo tanto no es conveniento utilizarlo en atributos quantitativos ni booleanos.
    Por ejemplo: admito nulos en el Cantidad de un Producto. Cuando agregue un Producto nuevo, se va a guardar Cantidad = NULL.
    ¿Que pasa si recibo 5 unidades y las quiero sumar el Inventario?
    Aquí se abren 2 nuevas posibilidades:
    • Genexus lee el valor, suma y guarda el resultado:
      Aquí Genexus nos oculta que existía un nulo y cuando lee el valor lo lee como cero, entonces 0 + 5 = 5
    • Genexus optimiza el update y lo genera en SQL:
      Update Productos set Cantidad = Cantidad + 5 = NULL
      NULL + 5 está indefinido por lo que resulta en NULL

Conclusiones:

Es importante prestar atención a la obligatoriedad de cada atributo y el posible uso de nulos. Utilizando las reglas detalladas en el cuadro anterior se obtiene un modelo de datos y base de conocimiento enriquecidos.
Agregando:
  • Información sobre obligatoriedad de los atributos
  • Atributos sin valores por defecto no representativos (Fechas mínimas, textos con un blanco o Blobs con valor 0x00).
  • Valores cuantitativos siempre válidos y evita errores sobre operaciones aritméticas

No hay comentarios: