Direkt zum Hauptinhalt

Definition einer modellgesteuerten Tabelle

Schema-ID: model-driven-entity@1 Maschinenlesbares Schema: model-driven-entity.schema.json

Die maßgebliche Klartextdarstellung einer Tabelle modellgesteuerter Apps. Sie ist die maßgebliche Quelle, gegen die eine Tabelle validiert wird – dieselbe Definition, die der Designer erzeugt, ein API-Aufruf übermittelt, ein KI-Assistent generiert und ein Lösungsimport mitbringt. Die Validierung wird für jede Herkunft identisch durchgesetzt, daher kann eine handgeschriebene oder generierte Datei, die diesem Schema entspricht, gefahrlos importiert werden.

Aufbau​

Eine Definition ist ein JSON-Objekt mit diesen Membern:

FeldTypPflichtHinweise
logicalNamestringjaMit Herausgeberpräfix, Snake-Case in Kleinbuchstaben (z. B. par_invoice).
displayNamestringjaBeschriftung im Singular (z. B. Invoice).
displayCollectionNamestringjaBeschriftung im Plural (z. B. Invoices).
iconstringneinSymbolschlüssel aus dem kuratierten Symbolsatz der Plattform, angezeigt neben der Tabelle in der Navigation einer App (§4.4). Weglassen für das Standardsymbol.
publisherPrefixstringjaKurzes Präfix in Kleinbuchstaben (z. B. par).
primaryFieldstringjaLogischer Name des Primärfelds (Namensfelds); muss in fields vorkommen.
primaryImagestringneinLogischer Name des Datensatzbilds (§6.16) – des Bilds, das in Rastern und Nachschlagefeldern neben einem Datensatz angezeigt wird. Muss ein Feld vom Typ Image in fields benennen. Weglassen für eine Tabelle ohne Bild.
secondaryFieldstring | nullneinLogischer Name des Felds, das als Sekundärtext des Datensatzes angezeigt wird – die kleinere zweite Zeile unter seinem Namen überall dort, wo Datensätze ohne Raster aufgelistet werden, etwa in einem Nachschlagebereich (§6.13.5). Muss ein Feld in fields benennen, das weder das Primärfeld noch eine Datei-/Bildspalte ist.
hierarchyParentFieldstring | nullneinLogischer Name des Nachschlagefelds, das diese Tabelle zu einer Hierarchie macht – des Felds, das das übergeordnete Element jedes Datensatzes enthält und auf dieselbe Tabelle zurückverweist (die übergeordnete Kategorie einer Kategorie, die übergeordnete Einheit einer Einheit). Muss ein Feld in fields vom Typ Lookup benennen, dessen targetEntity diese Tabelle ist. Es gewährt nichts und erzwingt nichts: Die Tabelle wird weiterhin als Raster gerendert, bis eine Ansicht ihre Datensätze verschachtelt. Es dient dazu, dass eine Hierarchie eine Eigenschaft der Daten ist und nicht einer einzelnen Ansicht – die oberste Ebene einer Baumansicht verwendet es als Standard für ihre Verknüpfung zu untergeordneten Elementen.
personFieldstringnullnein
constraintsarrayneinRegeln, die die Datenbank durchsetzt, nicht die Anwendung (siehe unten) – eine eindeutige Spalte oder ein Zeitraum, der sich nicht mit einem anderen im selben Geltungsbereich überschneiden darf.
fieldsarrayjaEine oder mehrere Felddefinitionen (siehe unten).
relationshipsarraynein1:n-Beziehungen, die auf Nachschlagefeldern beruhen.
isAuditEnabledbooleanneinAktiviert die Änderungsüberwachung für die Tabelle (Abschnitt 6.5). Standard ist false.
statesarrayneinDie Status, in denen sich ein Datensatz dieser Tabelle befinden kann (§6.14) – sein Lebenszyklus. Siehe unten. Fehlt in einem Dokument, das geschrieben wurde, bevor es Status gab; daran unterscheidet ein Importer es von einer Tabelle ohne Status.
reasonsarrayneinDie Gründe, von denen jeder zu genau einem Status gehört. Siehe unten.
statusValueBaseintegerneinDie Untergrenze des Bereichs, aus dem die hinzugefügten Status- und Grundoptionen dieser Tabelle nummeriert werden – die Optionswert-Basis des besitzenden Herausgebers (§6.14). Die vorbelegten Werte Aktiv/Inaktiv liegen außerhalb davon bei 0 und 1: Jede Tabelle hat sie, und sie bedeuten überall dasselbe, brauchen also keinen Namensraum.
nextStatusValueintegerneinDer Höchststand der Statuswerte der Tabelle – der nächste Wert, den sie vergibt. Gespeichert statt abgeleitet aus den Optionen, aus demselben Grund wie bei einem Optionssatz: Die Nummer einer entfernten Option ist stillgelegt, und eine erneute Ableitung würde sie an die nächste neue Option vergeben, während Datensätze sie womöglich noch enthalten.

Feld​

FeldTypPflichtHinweise
logicalNamestringjaSnake-Case in Kleinbuchstaben.
displayNamestringja
dataTypestringjaEiner von Text, MultilineText, Integer, Decimal, Boolean, DateTime, Lookup, PolymorphicLookup, File, Image, OptionSet, State, Reason.
isRequiredbooleannein
isPrimarybooleanneintrue für das eine Primärfeld.
maxLengthintegerneinFür Text (1–4000).
precision, scaleintegerneinFür Decimal (scale ≤ precision ≤ 38).
targetEntitystringbedingtPflicht, wenn dataType Lookup ist; der logische Name der referenzierten Tabelle.
targetEntitiesstring[]bedingtPflicht, wenn dataType PolymorphicLookup ist; die Tabellen, auf die ein Wert zeigen darf, in der Reihenfolge der Auswahl. Mindestens zwei, keine doppelt.
isAuditExcludedbooleanneinNimmt das Feld von der Änderungsüberwachung aus, wenn die Tabelle überwacht wird (Abschnitt 6.5). Standard ist false.

PolymorphicLookup-Felder werden als zwei Spalten angelegt: die eigene uuid-Spalte des Felds mit der ID des Datensatzes und eine benachbarte text-Spalte <column>_type mit dem logischen Namen der Zieltabelle. Keine von beiden trägt einen Fremdschlüssel – eine einzelne Spalte kann nicht auf mehrere Tabellen verweisen –, die Integrität liegt also beim Schreibpfad: Er prüft, ob das Ziel existiert, und ein danach gelöschtes Ziel wird als nicht aufgelöster Verweis gelesen.

Auf dem Transportweg reisen die beiden Hälften als ein Skalar, <table>:<id>, sodass die values eines Datensatzes eine flache Zuordnung von logischem Feldnamen zu Skalar bleiben und die Diskriminatorspalte nie als Feld auftaucht. Das ist die bestehende Konvention der Plattform für einen selbstbeschreibenden Verweis (recordfile:<id>, webresource:par_/app.js).

Gespeichert wird der logische Name der Tabelle und keine Zahl, denn ein numerischer Diskriminator wäre ein Index in targetEntities – eine Umsortierung der Ziele im Designer würde also stillschweigend jede gespeicherte Zeile auf eine andere Tabelle umleiten. Die Besitzer-Spalten eines Datensatzes verwenden dagegen eine numerische Aufzählung, was konsistent und kein Widerspruch ist: Ihre fünf Werte sind im Code festgelegte Plattformkonzepte, keine Liste, die ein Ersteller bearbeitet.

Jeder Eintrag in targetEntities erhält seine eigene zugrunde liegende Beziehung; dadurch bietet das Formular der referenzierten Tabelle für diese Datensätze eine Registerkarte Verwandt an.

File-/Image-Felder werden als Textspalte angelegt, die einen Verweis mit Schema-Präfix enthält – recordfile:<id> für eine Datei im eigenen Schema der Umgebung oder objectstore:<key> für eine, die groß genug war, um in den Object Storage ausgelagert zu werden. Die Bytes werden an den eigenen Dateiendpunkt des Felds hochgeladen statt über die Datensatz-API geschrieben und unter der Autorisierung des Datensatzes selbst ausgeliefert. Welcher der beiden Speicher eine Datei enthält, entscheidet ihre Größe und nichts, was ein Ersteller einstellt.

Beziehung​

FeldTypPflichtHinweise
logicalNamestringjaSnake-Case in Kleinbuchstaben.
typestringjaOneToMany.
referencedEntitystringjaDie „1“-Seite.
referencingEntitystringjaDie „n“-Seite (trägt das Nachschlagefeld).
lookupFieldstringjaDas Nachschlagefeld auf der referenzierenden Tabelle, auf dem die Beziehung beruht.

Status und Grund​

Ein Status gibt an, wo sich ein Datensatz in seinem Lebenszyklus befindet; ein Grund sagt, in welcher Ausprägung dieses Status er sich befindet. Sie reisen mit der Tabelle, weil sie Teil dessen sind, was der Ersteller entworfen hat.

🔴 Sie sind kein Optionssatz. Active auf einer Rechnung und Active auf einem Kontakt sind nicht dieselbe Auswahl, und sie als eine gemeinsame Liste zu modellieren, würde bedeuten, dass das Umbenennen des einen auch das andere umbenennt.

Status:

FeldTypPflichtHinweise
valueintegerjaDer gespeicherte Wert, bei einem Import beibehalten: Die Datensätze der Quellumgebung enthalten ihn bereits, also müssen Entwicklung und Test darin übereinstimmen, was er bedeutet.
displayNamestringjaDie Beschriftung.
colorstringneinDie Farbe, in der sein Badge gezeichnet wird.
iconstringneinDas Symbol auf seinem Badge.
defaultReasonintegerneinWelchen der Gründe dieses Status ein Datensatz erhält, der in ihn wechselt. Fehlt die Angabe, ist es der erste – deshalb ist die Einstellung optional.

Grund:

FeldTypPflichtHinweise
stateintegerjaDer value des Status, zu dem dieser Grund gehört. Über den Wert statt über die Zeilen-ID verknüpft, denn der Wert ist das, was ein Datensatz speichert und was einen Export übersteht.
valueintegerjaDer gespeicherte Wert.
displayNamestringjaDie Beschriftung.
color · iconstringneinWie bei einem Status.

Genau um diese Zugehörigkeit geht es: Won und Lost sind beides Gründe dafür, dass ein Geschäft inaktiv ist, und sie anzubieten, solange es aktiv ist, wäre unsinnig.

Beispiel​

{
"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" }
]
}

Versionierung​

Ältere Schemaversionen werden neben neuen aufbewahrt, sodass bereits bereitgestellte Lösungen weiterhin validiert werden, nachdem sich das Schema weiterentwickelt hat. Ist eine inkompatible Änderung nötig, wird eine neue Version (model-driven-entity@2) veröffentlicht, statt diese zu bearbeiten.