Saltar al contenido principal

Definición de entidad basada en modelo

Id del esquema: model-driven-entity@1 Esquema legible por máquina: model-driven-entity.schema.json

La representación canónica, en texto plano, de una entidad de las aplicaciones basadas en modelo. Es la fuente de verdad con la que se valida una entidad: la misma definición que produce el diseñador, que envía una llamada a la API, que genera un asistente de IA y que transporta una importación de solución. La validación se aplica de forma idéntica sea cual sea el origen, así que un archivo escrito a mano o generado que cumpla este esquema puede importarse con seguridad.

Forma​

Una definición es un objeto JSON con estos miembros:

CampoTipoObligatorioNotas
logicalNamestringsíCon el prefijo del editor, en snake_case en minúsculas (p. ej., par_invoice).
displayNamestringsíEtiqueta en singular (p. ej., Invoice).
displayCollectionNamestringsíEtiqueta en plural (p. ej., Invoices).
iconstringnoClave de icono del conjunto de iconos seleccionado de la plataforma, que se muestra junto a la tabla en la navegación de una aplicación (§4.4). Omítala para usar el glifo predeterminado.
publisherPrefixstringsíPrefijo corto en minúsculas (p. ej., par).
primaryFieldstringsíNombre lógico del campo principal (nombre); debe aparecer en fields.
primaryImagestringnoNombre lógico de la imagen del registro (§6.16): la imagen que se muestra junto a un registro en cuadrículas y búsquedas. Debe nombrar un campo de tipo Image en fields. Omítalo en una tabla sin imagen.
secondaryFieldstring | nullnoNombre lógico del campo que se muestra como texto secundario del registro: la segunda línea, más pequeña, bajo su nombre allí donde los registros se listan sin cuadrícula, como en un panel de búsqueda (§6.13.5). Debe nombrar un campo de fields que no sea el campo principal ni una columna File/Image.
hierarchyParentFieldstring | nullnoNombre lógico de la búsqueda que convierte esta tabla en una jerarquía: el campo que contiene el padre de cada registro y que apunta de vuelta a esta misma tabla (la categoría padre de una categoría, la unidad padre de una unidad). Debe nombrar un campo de fields de tipo Lookup cuyo targetEntity sea esta tabla. No concede nada ni impone nada: la tabla se sigue mostrando como una cuadrícula hasta que una vista anida sus registros. Sirve para que ser una jerarquía sea una propiedad de los datos y no de una vista concreta: el nivel superior de una vista de árbol usa este campo como vínculo hijo predeterminado.
personFieldstringnullno
constraintsarraynoReglas que aplica la base de datos, no la aplicación (vea más abajo): una columna única, o un periodo que no puede solaparse con otro del mismo ámbito.
fieldsarraysíUna o varias definiciones de campo (vea más abajo).
relationshipsarraynoRelaciones de uno a varios respaldadas por campos de búsqueda.
isAuditEnabledbooleannoHabilita la auditoría de cambios para la entidad (sección 6.5). El valor predeterminado es false.
statesarraynoLos estados en los que puede estar un registro de esta tabla (§6.14): su ciclo de vida. Vea más abajo. Ausente en un documento escrito antes de que existieran los estados, que es como un importador lo distingue de una tabla sin ninguno.
reasonsarraynoLos motivos, cada uno de los cuales pertenece exactamente a un estado. Vea más abajo.
statusValueBaseintegernoEl límite inferior del rango desde el que se numeran las opciones de estado y motivo añadidas de esta tabla: la base de valores de opción del editor propietario (§6.14). Los valores Active/Inactive creados de serie quedan fuera de él, en 0 y 1: todas las tablas los tienen y significan lo mismo en todas partes, así que no necesitan espacio de nombres.
nextStatusValueintegernoLa marca máxima de estado de la tabla: el siguiente valor que asignará. Se almacena en lugar de derivarse de las opciones, por el mismo motivo que en un conjunto de opciones: el número de una opción eliminada queda retirado, y volver a derivarlo se lo daría a la siguiente opción nueva mientras algunos registros aún podrían contenerlo.

Campo​

CampoTipoObligatorioNotas
logicalNamestringsíEn snake_case en minúsculas.
displayNamestringsí
dataTypestringsíUno de Text, MultilineText, Integer, Decimal, Boolean, DateTime, Lookup, PolymorphicLookup, File, Image, OptionSet, State, Reason.
isRequiredbooleanno
isPrimarybooleannoVerdadero para el único campo principal.
maxLengthintegernoPara Text (1–4000).
precision, scaleintegernoPara Decimal (scale ≤ precision ≤ 38).
targetEntitystringcondicionalObligatorio cuando dataType es Lookup; el nombre lógico de la entidad a la que se hace referencia.
targetEntitiesstring[]condicionalObligatorio cuando dataType es PolymorphicLookup; las tablas a las que puede apuntar un valor, en el orden del selector. Al menos dos, sin repeticiones.
isAuditExcludedbooleannoExcluye el campo de la auditoría de cambios cuando la entidad se audita (sección 6.5). El valor predeterminado es false.

Los campos PolymorphicLookup se aprovisionan como dos columnas: la propia columna uuid del campo, que contiene el id del registro, y una columna hermana <column>_type de tipo text, que contiene el nombre lógico de la tabla de destino. Ninguna de las dos tiene clave externa —una sola columna no puede hacer referencia a varias tablas—, así que la integridad depende de la ruta de escritura: comprueba que el destino existe, y un destino eliminado después se lee como una referencia sin resolver.

En la transmisión, las dos mitades viajan como un único escalar, <table>:<id>, de modo que los values de un registro siguen siendo un mapa plano de nombre lógico de campo a escalar y la columna discriminadora nunca aparece como campo. Es la convención ya existente en la plataforma para una referencia autodescriptiva (recordfile:<id>, webresource:par_/app.js).

Se almacena el nombre lógico de la tabla y no un número, porque un discriminador numérico sería un índice en targetEntities, de modo que reordenar los destinos en el diseñador haría apuntar en silencio cada fila almacenada a otra tabla. Las columnas de propietario de un registro usan en cambio una enumeración numérica, lo cual es coherente y no contradictorio: sus cinco valores son conceptos de la plataforma fijados en el código, no una lista que edite un creador.

Cada entrada de targetEntities tiene su propia relación de respaldo, que es lo que hace que el formulario de la tabla referenciada ofrezca una pestaña Relacionado para estos registros.

Los campos File / Image se aprovisionan como una columna de texto que contiene una referencia con esquema: recordfile:<id> para un archivo guardado en el propio esquema del entorno, u objectstore:<key> para uno lo bastante grande como para haberse desbordado al almacenamiento de objetos. Los bytes se cargan en el propio endpoint de archivos del campo, en lugar de escribirse a través de la API de registros, y se sirven con la autorización del propio registro. Cuál de los dos almacenes contiene un archivo lo decide su tamaño y nada que configure un creador.

Relación​

CampoTipoObligatorioNotas
logicalNamestringsíEn snake_case en minúsculas.
typestringsíOneToMany.
referencedEntitystringsíEl lado «uno».
referencingEntitystringsíEl lado «varios» (contiene la búsqueda).
lookupFieldstringsíEl campo de búsqueda de la entidad que hace referencia y que respalda la relación.

Estado y motivo​

Un estado indica en qué punto de su ciclo de vida está un registro; un motivo indica qué variante de ese estado tiene. Viajan con la tabla porque forman parte de lo que diseñó el creador.

🔴 No son un conjunto de opciones. Active en una factura y Active en un contacto no son la misma opción, y modelarlos como una lista compartida haría que cambiar el nombre de uno cambiara el del otro.

Estado:

CampoTipoObligatorioNotas
valueintegersíEl valor almacenado, que se conserva en una importación: los registros del entorno de origen ya lo contienen, así que Desarrollo y Pruebas deben coincidir en lo que significa.
displayNamestringsíLa etiqueta.
colorstringnoEl color con el que se dibuja su distintivo.
iconstringnoEl glifo de su distintivo.
defaultReasonintegernoCuál de los motivos de este estado recibe un registro al entrar en él. Si falta, es el primero, lo que hace que este ajuste sea opcional.

Motivo:

CampoTipoObligatorioNotas
stateintegersíEl value del estado al que pertenece este motivo. Se identifica por valor y no por id de fila, porque el valor es lo que almacena un registro y lo que sobrevive a una exportación.
valueintegersíEl valor almacenado.
displayNamestringsíLa etiqueta.
color · iconstringnoIgual que en un estado.

Lo esencial es la pertenencia: Won y Lost son ambos motivos por los que una oportunidad está inactiva, y ofrecerlos mientras está activa no tendría sentido.

Ejemplo​

{
"logicalName": "par_invoice",
"displayName": "Invoice",
"displayCollectionName": "Invoices",
"publisherPrefix": "par",
"primaryField": "par_name",
"fields": [
{ "logicalName": "par_name", "displayName": "Name", "dataType": "Text", "isPrimary": true, "isRequired": true, "maxLength": 200 },
{ "logicalName": "par_total", "displayName": "Total", "dataType": "Decimal", "precision": 18, "scale": 2 },
{ "logicalName": "par_account", "displayName": "Account", "dataType": "Lookup", "targetEntity": "par_account" }
],
"relationships": [
{ "logicalName": "par_account_invoices", "type": "OneToMany", "referencedEntity": "par_account", "referencingEntity": "par_invoice", "lookupField": "par_account" }
]
}

Control de versiones​

Las versiones anteriores del esquema se conservan junto a las nuevas para que las soluciones ya implementadas sigan validándose después de que el esquema evolucione. Cuando se necesita un cambio incompatible, se publica una versión nueva (model-driven-entity@2) en lugar de editar esta.