Clases del modelo de datos
ORDA permite crear funciones de clase de alto nivel sobre el modelo de datos. Esto le permite escribir código orientado al negocio y "publicarlo" como una API. Los almacenes de datos, las clases de datos, las selecciones de entidades y las entidades están disponibles como objetos de clase que pueden contener funciones.
Por ejemplo, podría crear una función getNextWithHigherSalary() en la clase EmployeeEntity para devolver los empleados con un salario superior al seleccionado. Sería tan sencillo como llamar:
$nextHigh:=ds.Employee.get(1).getNextWithHigherSalary()
Los desarrolladores no sólo pueden utilizar estas funciones en almacenes de datos locales, sino también en arquitecturas cliente/servidor y remotas:
//$cityManager es la referencia de un datastore remoto
Form.comp.city:=$cityManager.City.getCityName(Form.comp.zipcode)
Gracias a esta funcionalidad, toda la lógica de negocio de su aplicación 4D puede ser almacenada como una capa independiente para que pueda ser fácilmente mantenida y reutilizada con un alto nivel de seguridad:
-
Puede "ocultar" la complejidad global de la estructura física subyacente y exponer únicamente funciones comprensibles y listas para usar.
-
Si la estructura física evoluciona, basta con adaptar el código de las funciones y las aplicaciones cliente seguirán llamándolas de forma transparente.
-
Los atributos alias de ORDA por defecto son no expuestos. Debe añadir la palabra clave
exposedantes de la palabra claveAliassi desea que el alias esté disponible para peticiones remotas.

Además, 4D precrea automáticamente las clases para cada objeto del modelo de datos disponible.
Arquitectura
ORDA ofrece clases genéricas expuestas a través del class store 4D, así como clases usuario (que extienden las clases genéricas) expuestas en el class store cs:

Todas las clases de modelo de datos ORDA se exponen como propiedades del class store cs. Las clases ORDA siguientes están disponibles:
| Class | Nombre del ejemplo | Instanciado por |
|---|---|---|
| cs.DataStore | cs.DataStore | comando ds |
| cs.DataClassName | cs.Employee | dataStore.DataClassName, dataStore["DataClassName"] |
| cs._DataClassName_Entity | cs.EmployeeEntity | dataClass.get(), dataClass.new(), entitySelection.first(), entitySelection.last(), entity.previous(), entity.next(), entity.first(), entity.last(), entity.clone() |
| cs._DataClassName_Selection | cs.EmployeeSelection | dataClass.query(), entitySelection.query(), dataClass.all(), dataClass.fromCollection(), dataClass.newSelection(), entitySelection.drop(), entity.getSelection(), entitySelection.and(), entitySelection.minus(), entitySelection.or(), entitySelection.orderBy(), entitySelection.orderByFormula(), entitySelection.slice(), Create entity selection |
Las clases usuario ORDA se almacenan como archivos de clase estándar (.4dm) en la subcarpeta Classes del proyecto (ver más abajo).
Además, las instancias de objeto de clases usuario de los modelos de datos ORDA se benefician de las propiedades y funciones de sus padres:
- un objeto de clase Datastore puede llamar las funciones de la clase genérica ORDA Datastore.
- un objeto de clase Dataclass puede llamar las funciones de la clase genérica ORDA Dataclass.
- un objeto de clase Entity selection puede llamar las funciones de la clase genérica ORDA Entity selection.
- un objeto de clase Entity puede llamar las funciones de la clase genérica ORDA Entity.
Descripción de la clase
Historia
| Lanzamiento | Modificaciones |
|---|---|
| 21 R3 | Support for the server keyword. |
| 19 R4 | Atributos alias en la Entity Class |
| 19 R3 | Atributos calculados en la Entity Class |
| 18 R5 | Las funciones de clase de modelo de datos no están expuestas a REST por defecto. Nuevas palabras clave exposed y local. |
Clase DataStore
Una base de datos 4D expone su propia clase DataStore en el class store cs.
- Extends: 4D.DataStoreImplementation
- Nombre de clase: cs.DataStore
Puede crear funciones en la clase DataStore que estarán disponibles a través del objeto ds.
Ejemplo
// cs.DataStore class
Class extends DataStoreImplementation
Function getDesc
$0:="Database exposing employees and their companies"
Esta función puede ser llamada:
$desc:=ds.getDesc() //"Database exposing..."
Clase DataClass
Cada tabla expuesta con ORDA ofrece una clase DataClass en el class store cs.
- Extends: 4D.DataClass
- Nombre de clase: cs.DataClassName (donde DataClassName es el nombre de la tabla)
- Ejemplo: cs.Employee
Ejemplo
// cs.Company class
Class extends DataClass
// Devuelve las empresas cuyos ingresos están por encima de la media
// Devuelve una selección de entidades relacionadas con la clase de datos Company
Function GetBestOnes()
$sel:=This.query("revenues >= :1";This.all().average("revenues"));
$0:=$sel
A continuación, puede obtener una selección de entidades de las "mejores" empresas ejecutando:
var $best : cs.CompanySelection
$best:=ds.Company.GetBestOnes()
Los atributos calculados se definen en la clase Entity.
Ejemplo con un datastore remoto
El catálogo City siguiente está expuesto en un datastore remoto (vista parcial):

La clase City ofrece una API:
// cs.City class
Class extends DataClass
Function getCityName($zipcode : Integer) -> $cityName : Text
var $zip : 4D.Entity
$zip:=ds.ZipCode.get($zipcode)
$cityName:=""
If ($zip#Null)
$cityName:=$zip.city.name
End if
La aplicación cliente abre una sesión en el datastore remoto:
$cityManager:=Open datastore(New object("hostname";"127.0.0.1:8111");"CityManager")
A continuación, una aplicación cliente puede utilizar la API para obtener la ciudad correspondiente al código postal (por ejemplo) a partir de un formulario:
Form.comp.city:=$cityManager.City.getCityName(Form.comp.zipcode)
Clase EntitySelection
Cada tabla expuesta con ORDA ofrece una clase EntitySelection en el class store cs.
- Extends: 4D.EntitySelection
- Nombre de clase: _DataClassName_Selection (donde DataClassName es el nombre de la tabla)
- Ejemplo: cs.EmployeeSelection
Ejemplo
// cs.EmployeeSelection class
Class extends EntitySelection
//Extraer los empleados con un salario superior a la media de esta selección de entidades
Function withSalaryGreaterThanAverage() : cs.EmployeeSelection
return This.query("salary > :1";This.average("salary")).orderBy("salary")
A continuación, puede obtener los empleados con un salario superior a la media en cualquier selección de entidades mediante la ejecución:
$moreThanAvg:=ds.Company.all().employees.withSalaryGreaterThanAverage()
Los filtros de selección de entidades restringidas se definen en la clase de datos .
Entity Class
Cada tabla expuesta con ORDA ofrece una clase Entity en el class store cs.
- Extends: 4D.Entity
- Nombre de clase: _DataClassName_Entity (donde DataClassName es el nombre de la tabla)
- Ejemplo: cs.CityEntity
Class constructor
Se puede definir un constructor de clase para una clase Entidad. El constructor de la clase se llama cada vez que se crea una entidad en memoria y puede utilizarse para inicializar algunos valores.
Para más información, consulte la sección Constructor de clase.
Atributos calculados
Las clases Entity permiten definir atributos calculados utilizando palabras clave específicas:
Función getattributeNameFunción setattributeNameFunction queryattributeNameFunción orderByattributeName
Para más información, consulte la sección Atributos calculados.
Atributos de tipo alias
Las clases Entity permiten definir atributos alias, normalmente sobre atributos relacionados, utilizando la palabra clave Alias:
Alias attributeName targetPath
Para más información, consulte la sección Atributos alias.
Ejemplo
// cs.CityEntity class
Class extends Entity
Function getPopulation() : Integer
return This.zips.sum("población")
Function isBigCity(): Boolean
// La función getPopulation() es utilizable dentro de la clase
devuelve This.getPopulation()>50000
Luego puede llamar este código:
var $cityManager; $city : Object
$cityManager:=Open datastore(New object("hostname";"127.0.0.1:8111");"CityManager")
$city:=$cityManager.City.getCity("Caguas")
If ($city.isBigCity())
ALERT($city.name + " is a big city")
End if
Reglas específicas
Al crear o editar clases de modelos de datos, debe prestar atención a las siguientes reglas:
-
Dado que se utilizan para definir nombres de clase DataClass automáticos en el class store cs, las tablas 4D deben nombrarse para evitar todo conflicto en el espacio de nombres cs. En particular:
- No dé el mismo nombre a una tabla 4D y a una clase de usuarios. En tal caso, el constructor de la clase usuario queda inutilizado (el compilador devuelve una advertencia).
- No utilice un nombre reservado para una tabla 4D (por ejemplo, "DataClass").
-
Al definir una clase, asegúrese de que la instrucción
Class extendscoincida exactamente con el nombre de la clase padre (recuerde que son sensibles a mayúsculas y minúsculas). Por ejemplo,Class extends EntitySelectionpara una clase de selección de entidades. -
No se puede instanciar un objeto de clase de modelo de datos con la palabra clave
new()(se devuelve un error). Debe utilizar una función regular como se muestra en la columnaInstantiated byde la tabla de clases ORDA. -
No puede sobrescribir una función de clase ORDA nativa del class store
4Dcon una función de clase usuario de modelo de datos.
Ejecución apropiativa
Cuando se compilan, las funciones de clase del modelo de datos se ejecutan:
- en procesos apropiativos o cooperativos (dependiendo del proceso de llamada) en aplicaciones monopuesto,
- en procesos apropiativos en las aplicaciones cliente/servidor (excepto si se utiliza la palabra clave
local, en cuyo caso depende del proceso llamante como en monopuesto).
Si su proyecto está diseñado para ejecutarse en cliente/servidor, asegúrese de que el código de la función de clase del modelo de datos es hilo seguro. Si se llama un código thread-unsafe, se lanzará un error en tiempo de ejecución (no se lanzará ningún error al momento de la compilación ya que la ejecución cooperativa está soportada en las aplicaciones monopuesto).
Class constructor
Historia
| Lanzamiento | Modificaciones |
|---|---|
| 20 R10 | Añadidos |
Sintaxis
// Entity class
Class constructor()
// código
No hay palabra clave final para el código de función class constructor. El lenguaje 4D detecta automáticamente el final del código de una función por la siguiente palabra clave Function o el final del archivo de clase.
Una función class constructor ORDA se activa justo después de que se cree una nueva entidad en memoria, sea cual sea la forma en que se cree. Es útil para establecer los valores iniciales para la instanciación de entidades, por ejemplo un ID personalizado.
Esta función sólo puede definirse al nivel de la entidad. Sólo puede haber una función constructor en una class entity (de lo contrario se devuelve un error).
Esta función class constructor ORDA no recibe ni devuelve parámetros. Sin embargo, puede utilizarlo para inicializar valores de atributos utilizando This. Tenga en cuenta que los valores inicializados por el constructor se anulan si el código llena los atributos correspondientes.
Una función class constructor ORDA es similar a una función class constructor usuario, con las siguientes diferencias:
- no se pueden pasar parámetros al constructor,
- no puede utilizar las palabras clave
shared,sessionosingleton, - no puede llamar a la palabra clave
Superdentro de la función, - el constructor de la clase no puede ser llamado utilizando la función
new()sobre una entidad (las entidades solo pueden ser creadas por funciones específicas, ver más abajo).
Comandos que activan las funciones Class constructor
La función Class constructor es activada por los siguientes comandos y funciones:
dataClass.new()dataClass.fromCollection()- REST API $method=update en un POST sin los parámetros
__KEYy `__STAMP - el Explorador de datos.
- La función
entity.clone()no activa el constructor de la clase de la entidad. - Los registros creados a nivel de la base de datos 4D utilizando comandos del lenguaje clásico 4D o acciones estándar no activan el Class constructor de la entidad.
Configuraciones remotas
When using a remote configurations, you need to pay attention to the following principle: in client/server the function can be called on the client or on the server, depending on the location of the calling code. Cuando se llama en el cliente, no se dispara de nuevo cuando el cliente intenta guardar la nueva entidad y envía una petición de actualización al servidor para crear en memoria en el servidor.
Dado que funciones como dataClass.fromCollection() pueden crear un gran número de entidades y, por tanto, disparar consecuentemente el Class constructor de la entidad, es necesario asegurarse de que el código del constructor no ejecuta procesamientos que consuman demasiado tiempo, por razones de rendimiento. En configuraciones remotas (ver más abajo), el código no debe lanzar múltiples peticiones al servidor.
Ejemplo 1
//cs.BookingEntity class
Class constructor()
This.departureDate:=Current date
This.arrivalDate:=Add to date(Current date; 0; 0; 2)
Ejemplo 2 (diagrama): cliente/servidor
Ejemplo 3 (diagrama): Qodly - Acción estándar
Ejemplo 4 (diagrama): Qodly - Acción estándar y valor de actualización en la nueva entidad creada
Example 5 (diagram): Qodly - Entity instantiated in a function
Atributos calculados
Generalidades
Un atributo calculado es un atributo de clase de datos con un tipo de datos que enmascara un cálculo. Clases 4D estándar implementa el concepto de propiedades calculadas con get (getter) y set (setter) accessor functions. Los atributos de las clases de datos ORDA se benefician de esta funcionalidad y la extienden con dos funcionalidades adicionales: query y orderBy.
Como mínimo, un atributo calculado requiere una función get que describa cómo se calculará su valor. Cuando se suministra una función getter para un atributo, 4D no crea el espacio de almacenamiento subyacente en el datastore sino que sustituye el código de la función cada vez que se accede al atributo. Si no se accede al atributo, el código nunca se ejecuta.
Un atributo calculado también puede implementar una función set, que se ejecuta cada vez que se asigna un valor al atributo. La función setter describe qué hacer con el valor asignado, normalmente redirigiéndolo a uno o más atributos de almacenamiento o en algunos casos a otras entidades.
Al igual que los atributos de almacenamiento, los atributos calculados pueden incluirse en búsquedas. Por defecto, cuando se utiliza un atributo calculado en una búsqueda ORDA, el atributo se calcula una vez por entidad examinada. En algunos casos esto es suficiente. Sin embargo, para un mejor rendimiento, especialmente en cliente/servidor, los atributos calculados pueden implementar una función query que se basa en los atributos reales de la clase de datos y se beneficia de sus índices.
Del mismo modo, los atributos calculados pueden incluirse en ordenaciones. Cuando se utiliza un atributo calculado en una ordenación ORDA, el atributo se calcula una vez por entidad examinada. Cuando se utiliza un atributo calculado en una ordenación ORDA, el atributo se calcula una vez por entidad examinada.
Cómo definir los atributos calculados
Se crea un atributo calculado definiendo un accesor get en la clase entity de la dataclass. El atributo calculado estará disponible automáticamente en los atributos de la dataclass y en los atributos de la entidad.
También pueden definirse en la clase entity otras funciones de atributos calculados (set, query y orderBy). Son opcionales.
Dentro de las funciones de atributos calculados, This designa la entidad. Los atributos calculados pueden utilizarse y manejarse como cualquier atributo de dataclass, es decir, serán procesados por las funciones de clase entity o clase entity selection.
Los atributos calculados ORDA no están expuestos por defecto. Para exponer un atributo calculado, añada la palabra clave
exposeda la definición de la función **get **.
get and set functions can have the
localproperty to optimize client/server processing.
Function get <attributeName>
Sintaxis
{local | server} {exposed} Function get <attributeName>({$event : Object}) -> $result : type
// code
La función getter es obligatoria para declarar el atributo calculado attributeName. Cada vez que se accede al atributo attributeName, 4D evalúa el código Function get y devuelve el valor $result.
Un atributo calculado puede utilizar el valor de otro(s) atributo(s) calculado(s). Las llamadas recursivas generan errores.
La función getter define el tipo de datos del atributo calculado gracias al parámetro $result. Se permiten los siguientes tipos resultantes:
- Scalar (text, boolean, date, time, number)
- Object
- Imagen
- BLOB
- Entity (por ejemplo, cs.EmployeeEntity)
- Entity selection (p.e. cs.EmployeeeSelection)
El parámetro $event contiene las siguientes propiedades:
| Propiedad | Tipo | Descripción |
|---|---|---|
| attributeName | Text | Nombre de atributo calculado |
| dataClassName | Text | Nombre de la clase de datos |
| kind | Text | "get" |
| resultado | Variant | Opcional. Añada esta propiedad con valor Null si desea que un atributo escalar devuelva Null |
For more information about the local and server keywords, please refer to the local and server section.
Ejemplos
- El campo calculado fullName:
Function get fullName($event : Object)-> $fullName : Text
Case of
: (This.firstName=Null) & (This.lastName=Null)
$event.result:=Null //use result to return Null
: (This.firstName=Null)
$fullName:=This.lastName
: (This.lastName=Null)
$fullName:=This.firstName
Else
$fullName:=This.firstName+" "+This.lastName
End case
- Un atributo calculado puede basarse en un atributo relativo a una entidad:
Function get bigBoss($event : Object)-> $result: cs.EmployeeEntity
$result:=This.manager.manager
- Un atributo calculado puede basarse en un atributo relacionado con una entity selection:
Function get coWorkers($event : Object)-> $result: cs.EmployeeSelection
If (This.manager.manager=Null)
$result:=ds.Employee.newSelection()
Else
$result:=This.manager.directReports.minus(this)
End if
Function set <attributeName>
Sintaxis
{local | server} Function set <attributeName>($value : type {; $event : Object})
// code
La función setter se ejecuta cada vez que se asigna un valor al atributo. Esta función suele procesar los valores de entrada y el resultado se envía entre uno o varios atributos.
El parámetro $value recibe el valor asignado al atributo.
El parámetro $event contiene las siguientes propiedades:
| Propiedad | Tipo | Descripción |
|---|---|---|
| attributeName | Text | Nombre de atributo calculado |
| dataClassName | Text | Nombre de la clase de datos |
| kind | Text | "set" |
| value | Variant | Valor a tratar por el atributo calculado |
For more information about the local and server keywords, please refer to the local and server section.
Ejemplo
Function set fullName($value : Text; $event : Object)
var $p : Integer
$p:=Position(" "; $value)
This.firstname:=Substring($value; 1; $p-1) // "" if $p<0
This.lastname:=Substring($value; $p+1)
Function query <attributeName>
Sintaxis
Function query <attributeName>($event : Object)
Function query <attributeName>($event : Object) -> $result : Text
Function query <attributeName>($event : Object) -> $result : Object
// code
Esta función soporta tres sintaxis:
-
Con la primera sintaxis, se maneja toda la consulta a través de la propiedad del objeto
$event.result. -
Con la segunda y tercera sintaxis, la función devuelve un valor en $result:
- Si $result es un texto, debe ser una cadena de consulta válida
- Si $result es un Objeto, debe contener dos propiedades:
Propiedad Tipo Descripción $result.query Text Cadena de búsqueda válida con marcadores de posición (:1, :2, etc.) $result.parameters Collection valores para marcadores
La función query se ejecuta cada vez que se lanza una consulta que utiliza el atributo calculado. Resulta útil personalizar y optimizar las consultas basándose en los atributos indexados. Cuando la función query no está implementada para un atributo calculado, la búsqueda es siempre secuencial (basada en la evaluación de todos los valores utilizando la función get <AttributeName>).
No se soportan las siguientes funcionalidades:
- llamar a una función
queryen los atributos calculados de tipo Entity o Entity selection,- utilizando la palabra clave
order byen la cadena de consulta resultante.
El parámetro $event contiene las siguientes propiedades:
| Propiedad | Tipo | Descripción |
|---|---|---|
| attributeName | Text | Nombre de atributo calculado |
| dataClassName | Text | Nombre de la clase de datos |
| kind | Text | "query" |
| value | Variant | Valor a tratar por el atributo calculado |
| operator | Text | Operador de búsqueda (ver también la función de clase query). Valores posibles: |
| resultado | Variant | Valor a tratar por el atributo calculado. Pase Null en esta propiedad si desea que 4D ejecute la consulta por defecto (siempre secuencialmente para los atributos calculados). |
Si la función devuelve un valor en $result y se asigna otro valor a la propiedad
$event.result, se da prioridad a$event.result.
Ejemplos
- Búsqueda en el atributo calculado fullName.
Function query fullName($event : Object)->$result : Object
var $fullname; $firstname; $lastname; $query : Text
var $operator : Text
var $p : Integer
var $parameters : Collection
$operator:=$event.operator
$fullname:=$event.value
$p:=Position(" "; $fullname)
If ($p>0)
$firstname:=Substring($fullname; 1; $p-1)+"@"
$lastname:=Substring($fullname; $p+1)+"@"
$parameters:=New collection($firstname; $lastname) // two items collection
Else
$fullname:=$fullname+"@"
$parameters:=New collection($fullname) // single item collection
End if
Case of
: ($operator="==") | ($operator="===")
If ($p>0)
$query:="(firstName = :1 and lastName = :2) or (firstName = :2 and lastName = :1)"
Else
$query:="firstName = :1 or lastName = :1"
End if
: ($operator="!=")
If ($p>0)
$query:="firstName != :1 and lastName != :2 and firstName != :2 and lastName != :1"
Else
$query:="firstName != :1 and lastName != :1"
End if
End case
$result:=New object("query"; $query; "parameters"; $parameters)
Ten en cuenta que el uso de marcadores de posición en consultas basadas en la entrada de texto del usuario es recomendado por razones de seguridad (ver la descripción de
query()).
Código de llamada, por ejemplo:
$emps:=ds.Employee.query("fullName = :1"; "Flora Pionsin")
- Esta función gestiona las consultas sobre el atributo calculado age y devuelve un objeto con parámetros:
Function query age($event : Object)->$result : Object
var $operator : Text
var $age : Integer
var $_ages : Collection
$operator:=$event.operator
$age:=Num($event.value) // integer
$d1:=Add to date(Current date; -$age-1; 0; 0)
$d2:=Add to date($d1; 1; 0; 0)
$parameters:=New collection($d1; $d2)
Case of
: ($operator="==")
$query:="birthday > :1 and birthday <= :2" // after d1 and before or egal d2
: ($operator="===")
$query:="birthday = :2" // d2 = second calculated date (= birthday date)
: ($operator=">=")
$query:="birthday <= :2"
//... other operators
End case
If (Undefined($event.result))
$result:=New object
$result.query:=$query
$result.parameters:=$parameters
End if
Código de llamada, por ejemplo:
// personas de entre 20 y 21 años (-1 día)
$twenty:=people.query("age = 20") // llama al case "=="
// personas de 20 años hoy
$twentyToday:=people.query("age === 20") // equivalente a people.query("age is 20")
Function orderBy <attributeName>
Sintaxis
Function orderBy <attributeName>($event : Object)
Function orderBy <attributeName>($event : Object)-> $result : Text
// code
La función orderBy se ejecuta siempre que sea necesario ordenar el atributo calculado. Permite ordenar el atributo calculado. Por ejemplo, puede ordenar fullName en función de los nombres y luego de los apellidos, o a la inversa.
Cuando la función orderBy no está implementada para un atributo calculado, la ordenación es siempre secuencial (basada en la evaluación de todos los valores utilizando la función get <AttributeName>).
No se soporta la llamada a una función
orderBysobre atributos calculados de tipo Entity class o Entity selection class.
El parámetro $event contiene las siguientes propiedades:
| Propiedad | Tipo | Descripción |
|---|---|---|
| attributeName | Text | Nombre de atributo calculado |
| dataClassName | Text | Nombre de la clase de datos |
| kind | Text | "orderBy" |
| value | Variant | Valor a tratar por el atributo calculado |
| operator | Text | "desc" o "asc" (por defecto) |
| descending | Boolean | true para orden descendente, false para orden ascendente |
| resultado | Variant | Valor a tratar por el atributo calculado. Pase Null si desea que 4D ejecute la ordenación por defecto. |
Puede utilizar el
operatoro la propiedaddescending. Es esencialmente una cuestión de estilo de programación (ver ejemplos).
Puede devolver la cadena orderBy en la propiedad del objeto $event.result o en el resultado de la función $result. Si la función devuelve un valor en $result y se asigna otro valor a la propiedad $event.result, se da prioridad a $event.result.
Ejemplo
Puede escribir código condicional:
Function orderBy fullName($event : Object)-> $result : Text
If ($event.descending=True)
$result:="firstName desc, lastName desc"
Else
$result:="firstName, lastName"
End if
También puede escribir un código compacto:
Function orderBy fullName($event : Object)-> $result : Text
$result:="firstName "+$event.operator+", "lastName "+$event.operator
El código condicional es necesario en algunos casos:
Function orderBy age($event : Object)-> $result : Text
If ($event.descending=True)
$result:="birthday asc"
Else
$result:="birthday desc"
End if
Atributos de tipo alias
Generalidades
Un atributo alias se crea sobre otro atributo del modelo de datos, denominado atributo de destino. El atributo de destino puede pertenecer a una clase de datos relacionada (disponible a través de todo número de niveles de relación) o a la misma clase de datos. Un atributo alias no almacena ningún dato, sino la ruta a su atributo de destino. Puede definir tantos atributos de alias como desee en una clase de datos.
Los atributos del alias son particularmente útiles para manejar las relaciones N a N. Aportan más legibilidad y simplicidad en el código y en las consultas al permitir basarse en conceptos de negocio en lugar de en detalles de implementación.
Cómo definir los atributos alias
Se crea un atributo alias en una dataclass utilizando la palabra clave Alias en la clase Entity de la dataclass.
Alias <attributeName> <targetPath>
Sintaxis
{exposed} Alias <attributeName> <targetPath>
attributeName debe cumplir las reglas estándar para nombres de propiedades.
targetPath es una ruta atributo que contiene uno o más niveles, como "employee.company.name". Si el atributo de destino pertenece a la misma clase de datos, targetPath es el nombre del atributo.
Un alias puede ser utilizado como parte de una ruta de otro alias.
Un atributo calculado puede utilizarse en una ruta alias, pero sólo como último nivel de la ruta; de lo contrario, se devuelve un error. Por ejemplo, si "fullName" es un atributo calculado, un alias con ruta "employee.fullName" es válido.
Los atributos alias de ORDA por defecto son no expuestos. Debe añadir la palabra clave
exposedantes de la palabra claveAliassi desea que el alias esté disponible para peticiones remotas.
Uso de los atributos alias
Los atributos alias son de sólo lectura (excepto cuando se basan en un atributo escalar de la misma clase de datos, ver el último ejemplo a continuación). Pueden utilizarse en lugar de la ruta de su atributo de destino en funciones de clase como:
| Function |
|---|
dataClass.query(), entitySelection.query() |
entity.toObject() |
entitySelection.toCollection() |
entitySelection.extract() |
entitySelection.orderBy() |
entitySelection.orderByFormula() |
entitySelection.average() |
entitySelection.count() |
entitySelection.distinct() |
entitySelection.sum() |
entitySelection.min() |
entitySelection.max() |
entity.diff() |
entity.touchedAttributes() |
Tenga en cuenta que los atributos alias se calculan en el servidor. En las configuraciones remotas, la actualización de los atributos alias en las entidades requiere que éstas se vuelvan a cargar desde el servidor.
Propiedades del alias
El atributo alias kind es "alias".
Un atributo alias hereda su propiedad de type del atributo objetivo:
- si el
kinddel atributo objetivo es "storage", el tipo de datos del alias es del mismo tipo, - si el
kinddel atributo objetivo es "relatedEntity" o "relatedEntities", el tipo de datos del alias es de tipo4D.Entityo4D.EntitySelection("_classname_Entity" o "_classname_Selection").
Los atributos alias basados en relaciones tienen una propiedad específica path, que contiene la ruta de sus atributos objetivos. Los atributos de alias basados en atributos de la misma clase de datos tienen las mismas propiedades que sus atributos de destino (y ninguna propiedad path).
Ejemplos
Considerando el siguiente modelo:

En la clase de datos Teacher, un atributo alias devuelve todos los alumnos de un profesor:
// cs.TeacherEntity class
Class extends Entity
Alias students courses.student //relatedEntities
En la clase Student, un atributo alias devuelve todos los profesores de un alumno:
// cs.StudentEntity class
Class extends Entity
Alias teachers courses.teacher //relatedEntities
En la dataclass Course:
- un atributo alias devuelve otra etiqueta para el atributo "name"
- un atributo alias devuelve el nombre del profesor
- un atributo alias devuelve el nombre del estudiante
// cs.CourseEntity class
Class extends Entity
Exposed Alias courseName name //scalar
Exposed Alias teacherName teacher.name //valor escalar
Exposed Alias studentName student.name //valor escalar
Luego puede ejecutar las siguientes consultas:
// Encontrar curso llamado "Arqueología"
ds.Course.query("courseName = :1"; "Arqueología")
// Encontrar cursos impartidos por el profesor Smith
ds.Course.query("teacherName = :1"; "Smith")
// Encontrar cursos donde asista el Alumno "Martin"
ds.Course.query("studentName = :1"; "Martin")
// Encontrar alumnos que tengan a M. Smith como profesor
ds.Student.query("teachers.name = :1"; "Smith")
// Encontrar profesores que tienen a M. Martin como alumno
ds.Teacher.query("students.name = :1"; "Martin")
// Observe que esta cadena de consulta tan simple procesa una consulta compleja
// que incluye un doble join, como puede ver en el queryPlan:
// "Join on Table : Course : Teacher.ID = Course.teacherID,
// subquery:[ Join on Table : Student : Course.studentID = Student.ID,
// subquery:[ Student.name === Martin]]"
También puede editar el valor del alias courseName:
// Renombrar un curso utilizando su atributo alias
$arch:=ds.Course.query("courseName = :1"; "Archaeology")
$arch.courseName:="Archaeology II"
$arch.save() //courseName y name son "Archaeology II"
Funciones expuestas y no expuestas
For security reasons, all of your data model class functions, including computed attributes and alias attributes, as well as shared singleton functions are not exposed (i.e., private) by default to remote requests.
Las peticiones remotas son:
- Las peticiones enviadas por las aplicaciones 4D remotas conectadas a través de
Open datastore - Peticiones REST, incluidas las solicitudes de páginas Qodly
Las peticiones cliente/servidor 4D estándar no se ven afectadas. Las funciones de clase del modelo de datos están siempre disponibles en esta arquitectura.
Una función que no está expuesta no está disponible en aplicaciones remotas y no se puede llamar a ninguna instancia de objeto desde una petición REST. Si una aplicación remota intenta acceder a una función no expuesta, se devuelve el error "-10729 - Método miembro desconocido".
Para permitir que una función o un atributo sea llamado por una petición remota, debe declararlo explícitamente utilizando la palabra clave exposed. La sintaxis formal es:
// declarar una función expuesta
exposed Function <functionName>
// declarar un alias expuesto
exposed Alias <attributeName> <targetPath>
// declare un atributo calculado expuesto
exposed Function get <attributeName>
// declara una función singleton compartida
shared singleton Class constructor()
exposed Function <functionName>
La palabra clave exposed solo puede utilizarse con los objetos descritos anteriormente. Si se utiliza con una función de clase usuario estándar, se ignora y el compilador devuelve un error.
Ejemplo
Desea que una función expuesta utilice una función privada de una clase dataclass:
Class extends DataClass
//Función pública
exposed Function registerNewStudent($student : Object) -> $status : Object
var $entity : cs.StudentsEntity
$entity:=ds.Students.new()
$entity.fromObject($student)
$entity.school:=This.query("name=:1"; $student.schoolName).first()
$entity.serialNumber:=This.computeSerialNumber()
$status:=$entity.save()
//función (privada) no expuesta
Function computeIDNumber() -> $id : Integer
//calcular un nuevo número de ID
$id:=...
Cuando se llama al código:
var $remoteDS; $student; $status : Object
var $id : Integer
$remoteDS:=Open datastore(New object("hostname"; "127.0.0.1:8044"); "students")
$student:=New object("firstname"; "Mary"; "lastname"; "Smith"; "schoolName"; "Math school")
$status:=$remoteDS.Schools.registerNewStudent($student) // OK
$id:=$remoteDS.Schools.computeIDNumber() // Error "Unknown member method"
Palabra clave onHTTPGet
Utilice la palabra clave onHTTPGet para declarar funciones que pueden ser llamadas a través de peticiones HTTP utilizando el verbo GET. Estas funciones pueden devolver cualquier contenido web, por ejemplo utilizando la clase 4D.OutgoingMessage.
La palabra clave onHTTPGet está disponible con:
- Funciones de las clases del modelo de datos ORDA
- Funciones de la clase Singletons
La sintaxis formal es:
// declarar una función onHTTPGet
exposed onHTTPGet Function <functionName>(params) : result
En este caso también debe añadirse la palabra clave exposed, de lo contrario se generará un error.
Como este tipo de llamada es una acción que se ofrece fácilmente, el desarrollador debe asegurarse de que no se realiza ninguna acción sensible en dichas funciones.
params
Una función con la palabra clave onHTTPGet acepta parámetros.
En la petición HTTP GET, los parámetros deben pasarse directamente en la URL y declararse utilizando la palabra clave $params (deben estar encerrados en una colección).
IP:port/rest/<dataclass>/functionName?$params='[<params>]'
Consulte la sección Parámetros en la documentación del servidor REST.
resultado
Una función con la palabra clave onHTTPGet puede devolver cualquier valor de un tipo soportado (igual que para parámetros REST).
Puede devolver un valor del tipo de clase 4D.OutgoingMessage para beneficiarse de las propiedades y funciones para definir el encabezado, el cuerpo y el estado de la respuesta.
Ejemplo
Ha definido la siguiente función:
Class extends DataClass
exposed onHTTPGet Function getThumbnail($name : Text; $width : Integer; $height : Integer) : 4D.OutgoingMessage
var $file := File("/RESOURCES/Images/"+$name+".jpg")
var $image; $thumbnail : Picture
var $response := 4D.OutgoingMessage.new()
READ PICTURE FILE($file.platformPath; $image)
CREATE THUMBNAIL($image; $thumbnail; $width; $height; Scaled to fit)
$response.setBody($thumbnail)
$response.setHeader("Content-Type"; "image/jpeg")
return $response
Se puede llamar mediante la siguiente petición HTTP GET:
IP:port/rest/Products/getThumbnail?$params='["Yellow Pack",200,200]'