¡Un espectáculo de magia te espera con los atributos computados de ORDA!

Traducido automáticamente de Deepl

A menudo es útil, o incluso esencial, que las bases de datos se adapten de forma flexible y evolutiva a los usuarios y a sus negocios en el mundo de la informática. El control de los datos accesibles es también un tema recurrente y delicado. Desde este punto de vista, los desarrolladores utilizan métodos y fórmulas a veces complejos para dar o restringir el acceso a la información, en función del contexto o de los derechos de acceso de los usuarios.

Pongamos un ejemplo sencillo. En su aplicación, a veces necesita mostrar una lista de personas. Una de las columnas muestra sus nombres completos, pero en su base de datos tiene un campo de nombre y otro de apellido. Actualmente, escribes una fórmula en la columna del cuadro de lista, y tienes que gestionar tú mismo la ordenación de la columna. ¿No sería genial tener un campo computado en el que pudiera definir su fórmula de cálculo y su método de ordenación, y tener toda la lógica de negocio dentro de la clase y no en cada interfaz?

Bueno, a partir de 4D v19 R3, 4D proporciona una solución a esto, con los atributos computados.

Atributos computados HDI ORDA

DEMO Atributos computados ORDA

IMAGINE…

Usted tiene una lista de personas cuyos apellidos, nombres, fechas de nacimiento, etc.

Imagine que quiere mostrar, en un formulario, una lista de personas con su nombre completo (basado en el nombre + el apellido), su edad (basada en la fecha de nacimiento), su foto actual (basada en su edad)…
Luego, en cuanto se selecciona una persona, se puede mostrar información sobre sus padres, abuelos, hijos, hermanos, tíos y no olvidemos a los primos.

¿Es esto posible? Sí, por supuesto.
¿Sin complicadas líneas de código en el formulario? Sí.

Toda esta magia es posible gracias a los atributos computados, sobre los cuales también es posible buscar y ordenar, ¡igual que con los otros atributos! Veámoslo con más detalle.

Definición y cálculos

Para explicar la potencia de este concepto, empezaremos con un ejemplo concreto. Una clase de datos «personas» contiene clásicamente atributos como «apellido», «nombre», «dirección», «código postal», «ciudad», «país», «fecha de nacimiento», etc.
De esta clase, podemos necesitar el nombre completo (apellido + nombre), la edad (basada en la fecha de nacimiento), o la dirección completa (como objeto).
E incluso podemos ir más allá. Si las relaciones lo permiten, los atributos computados pueden ser incluso del tipo de entidad (por ejemplo, padre o madre) o de selección de entidades (hijos, padres, abuelos, hermanos, etc.).

El acceso a estos atributos será posible a través de la clase «peopleEntity», en la que habrá que definir nuevas funciones para ello.

Serán llamados cuando 4D necesite acceder a estos atributos, ya sea para leerlos (por ejemplo, una simple visualización), durante una búsqueda o una ordenación y, finalmente, durante un posible guardado tras una modificación.
El resultado de los atributos computados, como la dirección completa, puede necesitar otro atributo computado, como el nombre completo. Este tipo de recursión también es posible; volveremos a hablar de ello.

Estas functions (get, set así como query y orderBy que se discutirán más adelante) se definirán dentro de la propia clase de entidad (ej: peopleEntity)

Acceso a los atributos computados

Obtener

La primera función, «get», permite definir la forma de calcular el atributo. Para ello, debe devolver el resultado del cálculo.
Esta función es la única que es obligatoria para utilizar los atributos computados. De hecho, sólo su presencia determina la existencia misma de este atributo.

Function get fullName($event : Object) -> $result : Text
If (This.firstname=Null)
$result :=This.lastname
Else
If (This.lastname=Null)
$result :=This.firstname
Else
$result :=This.firstname+" "+This.lastname
End if
End if

¿Expuesto, local … o no?

¿Cómo será accesible este atributo y bajo qué condiciones se calculará?

La palabra clave «expuesto» que se puede utilizar para definir la función es el equivalente a la casilla «Expuesto» del inspector del editor de estructuras.

blank

La palabra clave «local» utilizada en el modo Cliente-Servidor determina si el cálculo debe realizarse sistemáticamente en el servidor o si debe llevarse a cabo localmente para limitar el acceso a la red.

SET

La segunda función, «set», permite la operación contraria para modificar los atributos reales a partir de un atributo calculado.
Si tomamos el ejemplo de fullname, la regla simple será buscar un espacio en el atributo para redistribuir el valor en firstname y lastname. Por supuesto, esto es sólo un ejemplo sencillo. Si el nombre completo contiene varios espacios, tendrá que aplicar una regla de negocio más compleja, como el uso de una barra (/), y tratarla como una prioridad.
Por ejemplo «Pablo Miguel/de la Casa del Mar».
La ventaja es que, una vez definida, esta regla se aplicará sistemáticamente sin tener que redefinirla en función del contexto de entrada.

Function set fullName($value: Text)
var $p : Integer
$p :=Position("/"; $value)
If ($p>0)
$p :=Position(" "; $value)
End if
If ($p>0)
This .firstname:=Substring($value; 1; $p-1)
This .lastname:=Substring($value; $p+1)
Else
This .firstname:="
This .lastname:=$value

End if

¿Un get sin set? Y lo contrario…

Una función Get es obligatoria para tener acceso a un atributo calculado. Una función Set es obligatoria para que este atributo sea modificable, pero ¿qué pasa si sólo existe una u otra de estas funciones?

Cuando sólo existe la función Get, el atributo se puede considerarde «sólo lectura » y no se puede modificar.

Cuando sólo existe Set, el atributo puede escribirse pero no puede releerse. Este es el principio de un buzón o una contraseña.

¿Qué es lo que sigue?

La tercera y cuarta funciones query y orderBy son bastante similares y se tratan de la misma manera.
Estas funciones no son obligatorias, pero su uso aumentará drásticamente las prestaciones, como veremos. De hecho, si estas funciones no están definidas, 4D tendrá que ejecutar la función «get » para cada entidad y luego realizar una ordenación secuencial. Esto es probable que pertenezca y estará lejos de ser optimizado.

Es esencial entender y recordar que los atributos computados no tienen índices. Sin embargo, si su cálculo se basa en atributos, entonces esos atributos pueden estar (o deberían estar) indexados.

Por esta razón, se ofrece la posibilidad de definir cómo debe realizarse la búsqueda cuando se lanza una consulta o una ordenación sobre un atributo computado.

Si tomamos el ejemplo de fullname, basado en los atributos firstname y lastname (ambos indexados), una búsqueda del tipo <<fullname = «Paul Smith» >> significará probablemente que <<firstname = «Paul»>> y <<lastname = «Smith»>>. Usted es libre de ampliar la búsqueda y decidir que una búsqueda <<fullname = «Pa Sm» >> significa que el <<firstname empieza por «Pa»>> y el <<lastname empieza por «Sm»>>. O que << = «Martin» >> significa que el apellido o el nombre empieza por «Martin»…

Consulta

Al ejecutar la función «query» definida para cualquier atributo computado, el parámetro recibido contendrá dos propiedades necesarias para entender la búsqueda deseada. Sabiendo esto, la consulta puede reescribirse para utilizar uno (o varios) atributos indexados y evitar así una búsqueda secuencial.

$event.operator contiene el operador en forma de cadena («==», «>=», «<«, etc.)
$event. Value contiene el valor a buscar o comparar, también en forma de cadena.

El resultado de una función de consulta puede ser una cadena o un objeto.

Si la función devuelve una cadena, ésta debe ser una consulta válida.

$result:="apellido = A@ y nombre = B@"

Si la función devuelve un objeto, debe contener dos propiedades:

  • .query: una cadena de consulta válida que puede contener marcadores de posición (:1,:2, etc.)
  • .parameters: una colección de valores que se utilizarán dentro de los marcadores de posición

$result:=New object("query"; $query; "parameters"; $parameters)

¡Veamos ahora cómo gestionar la siguiente consulta de clase de datos dentro de la función query!

$es:=ds.people.query("fullname = :1"; "Paul Smith")

Aquí está el código completo de la función de consulta:

Function query fullname ($event: Object) -> $result: Object
$fullname :=$event.valor
$operator :=$event.operador
$p :=Position(" "; $fullname)
If ($p>0)
$firstname :=Substring($fullname; 1; $p-1)+"@"
$lastname :=Substring($fullname; $p+1)+"@"
$parameters :=New collection($firstname; $lastname)
Else
$fullname :=$fullname+"@"
$parameters :=New collection($fullname)
End if

Case of

: ¡($operator="==") | ($operator="===")
If ($p>0)
$query :="nombre = :1 y apellido = :2"
Else
$query :="nombre = :1 o apellido = :1"
End if
: ($operator="!=")
If ($p>0)
$query :="nombre != :1 y apellido != :2"
Else
$query :="nombre != :1 y apellido != :1"
End if
End case
$result :=New object("consulta"; $query; "parámetros"; $parameters)

Ordenar por

En cuanto a la ordenación, es bastante similar. En este caso, ordenar a las personas por su edad es precisamente lo mismo que ordenarlas por su fecha de nacimiento revertida. Así que cuando se solicite una ordenación por edad, será inteligente utilizar la fecha de nacimiento, que está indexada como criterio.

  • Ordenar por muestras:

$es:=ds.people.all().orderBy("age desc")
$es :=ds.people.all().orderBy("edad asc")

  • Función OrderBy:

Function orderBy age($event: Object) -> $result: String
If
($event.operator = "desc")
$result :="cumpleaños asc"
Else
$result
:="cumpleaños desc"
End if

Uso de índices compuestos

Los índices compuestos pueden utilizarse de forma muy positiva en algunos casos. Recordatorio: Una ordenación por «apellido» y «nombre» no utiliza el índice del apellido ni el del nombre. Para que este tipo de ordenación se optimice, debe haber un índice nombre anterior+nombre, o nombre+apellido… o ambos.

En el caso de un atributo computado como fullname, 4D utilizará este índice compuesto si es consciente de que se trata de una ordenación nombre+apellido. Incluso es posible forzar una ordenación por apellido + nombre, ¡ aunque el nombre completo muestre el nombre antes que el apellido!

  • Ordenar por ejemplo:

Form.people:=ds.people.all().orderBy("fullname asc")

  • Función OrderBy:

Function orderBy fullname($event : Object)->$result : Text
If ($event.descending)
$result :="lastname desc, firstname desc"
Else
$result :="lastname asc, firstname asc"
End if

Otros tipos posibles de atributos COMPUTED

En las secciones anteriores, hemos cubierto los atributos computados de tipo escalar (texto, numérico…), ¡pero los atributos computados también pueden ser objetos, entidades o selecciones de entidades!

Algunos ejemplos posibles:

  • fullAddress: objeto con tantos atributos como sea necesario (nombre completo, calle, código postal, ciudad, país, etc.)

Function get fullAddressThis($event: Object) -> $result: Object
$result :=New object
$result .fullName:=This.fullName // Another computed attribute can be used!
$result .address:=This.address
$result .zipCode:=This.zipCode
$result .city:=This.city
$result.state:=This.state
$result .country:country

  • bigBoss: entidad

Function get bigBoss($event: Object) -> $result: cs.peopleEntity
$result :=this.manager.manager

  • compañeros de trabajo : entidadSelección

Function get coworkers($event: Object) -> $result: cs.peopleEntitySelection
$result :=this.manager.directReports.minus(this)

Conclusión

Losatributos computarizados han nacido y están bien nacidos. Aportan tanto flexibilidad y potencia como un mayor control sobre lo que es accesible o no. El acceso a estos atributos está optimizado para no penalizar ni la memoria ni el acceso a la red. Son la solución sencilla a las demandas de las empresas y responden a las mayores exigencias de la programación moderna.

Para más detalles, lea esta documentación.

Roland Lannuzel
- Propietario de Producto y Experto en 4D - Después de estudiar electrónica, Roland se dedicó a la informática industrial como desarrollador y consultor, construyendo soluciones para clientes con una variedad de bases de datos y tecnologías. A finales de los años 80 se enamoró de 4D y lo ha utilizado para escribir aplicaciones de negocio que incluyen sistemas de contabilidad, facturación y correo electrónico.Eventualmente se unió a la compañía en 1997, las valiosas contribuciones de Roland incluyen el diseño de especificaciones, herramientas de prueba, demos, así como la formación y hablar con la comunidad 4D en muchas conferencias. Continúa dando forma activamente al futuro de 4D definiendo nuevas características y herramientas de desarrollo de bases de datos.