A Mendix SDK-Grundlagen – Teil 1
Der Mendix Modell-SDK, unterstützt durch die Mendix Platform SDK ist ein Tool, das es schon seit Jahren gibt. Sein Zweck besteht darin, Entwicklern programmgesteuerten Zugriff auf das Modell eines Mendix App, ohne Studio oder Studio Pro zu verwenden.
In dieser kurzen Serie werde ich zeigen, wie SDKs verwendet werden können, um nützliche Operationen an einer App durchzuführen. Dieser erste Beitrag soll Ihnen den Einstieg erleichtern, indem er Einrichten einer Entwicklungsumgebung mit NodeJS ein TypeScript-Skript erstellen zur Verwendung des SDK sowie die Ausführung dieses Skripts.
Ich beabsichtige nicht, dies als TypeScript/JavaScript-Tutorial zu nutzen (ich bin kaum in der Lage, das zu tun, und es gibt viele gute Ressourcen online) und Ich werde mich auf die Aspekte des SDK konzentrieren und nicht die Codedetails.

Warum möchten Sie möglicherweise das SDK verwenden?
Es gibt eine Vielzahl von Anwendungsfällen, die die Mendix Das Model SDK unterstützt unter anderem:
Die Extraktion der Details eines gesamten oder eines Teils des App-Modells zur Übersetzung in ein anderes Medium. Beispielsweise möchten Sie möglicherweise Informationen aus dem Modell extrahieren, um Ihre eigene Dokumentation zu erstellen, oder Sie möchten möglicherweise die Logik in Mikroflüssen extrahieren. Äquivalente in einer anderen Sprache bilden wie JavaScript oder C#.
Die automatisierte Aktualisierung von Apps, um die Einhaltung von Entwicklungs- oder Sicherheitsstandards zu erzwingen. Beispielsweise möchten Sie möglicherweise allgemeine Microflow-/Nanoflow-Benennungsstandards durchsetzen oder verlangen, dass auf Entitäten entsprechende Mindestzugriffsberechtigungen angewendet werden.
Die automatisierte Erstellung von Code, Seiten, Entitäten usw. in einer App aus parametrisierten Eingaben. Beispielsweise möchten Sie möglicherweise den Vorgang des Kopierens der Struktur oder des Schemas einer Datenquelle automatisieren und in eine Mendix App.
Entwicklungsumgebung
Entwickler haben ihre eigenen Vorlieben, wenn es um Tools geht. Sie benötigen mindestens NodeJS und einen Skripteditor – ich verwende zum Bearbeiten Visual Studio Code, verfügbar unter Visual Studio Code, da mir die TypeScript-Unterstützung gefällt. Ich werde keine ausgefallene Einrichtung und Konfiguration für die Umgebung vorschlagen, sondern die Dinge einfach halten – ein einzelner Ordner für die Skripte, die ich erstelle.
Auf der Dokumentationsseite ist umfangreiche Dokumentation zu den Plattform- und Modell-SDKs verfügbar: Mendix Plattform-SDK.
NodeJS-Installation
Laden Sie die neueste stabile Version von NodeJS herunter und installieren Sie sie unter KnotenJS mit der englischsprachigen Download-Seite unter NodeJS Englische Downloads.
Wenn Sie bereits eine frühere Version von NodeJS installiert haben und diese behalten möchten, können Sie ein Tool wie den NodeJS Version Manager „nvm“ verwenden, mit dem Sie mehrere Versionen von NodeJS installieren und verwalten und zwischen ihnen wechseln können. Eine Auswahl von Paketmanagern finden Sie unter NodeJS-Paketmanager.
Erstellen Sie einen Arbeitsordner und initialisieren Sie ihn
Als Nächstes brauche ich einen Ort, an dem ich meine Arbeit ablegen kann. Deshalb erstelle ich einen Arbeitsordner. Anschließend initialisiere ich ihn mit dem NodeJS-Paketmanager und stelle sicher, dass das TypeScript-Paket installiert ist.
mkdir SDKBlog cd SDKBlog npm init --yes npm install -g typescript
Wechseln Sie anschließend zu Ihrem Editor und erstellen oder bearbeiten Sie eine Datei im Ordner namens paket.json und ändern Sie diese Datei, um Abhängigkeiten für die SDK-Pakete einzuschließen. Sie sollte ungefähr so aussehen:
{
"name": "sdkblog",
"version": "1.0.0",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"mendixmodelsdk": "^4.56.0",
"mendixplatformsdk": "^5.0.0"
},
"devDependencies": {},
"description": ""
}
Laden Sie die SDK-Pakete mit npm install herunter. Dadurch wird ein Unterordner mit dem Namen 'node_modules', wo eine Hierarchie verschiedener Paketdateien gespeichert wird.
npm installieren
Schließlich haben Erstellen oder bearbeiten Sie eine tsconfig.json Datei um die Compileroptionen und den Namen der zu erstellenden TypeScript-Datei anzugeben. Jedes Mal, wenn Sie dem Ordner eine neue TypeScript-Datei hinzufügen, können Sie sie der Datei tsconfig.json hinzufügen. Wenn Sie dann den TypeScript-Compilerbefehl „tsc“ ausführen, werden alle Dateien in JavaScript kompiliert, sodass sie ausgeführt werden können.
{
"compilerOptions" : {
"module" : "commonjs",
"target" : "es2020",
"strict": true
},
"files" : [
"showdocument.ts"
]
}
Erhalten Sie einen persönlichen Zugriffstoken
Sie müssen zu gehen Mendix Warden-Site bei Mendix Aufseher. Dort müssen Sie sich mit Ihrem Mendix Anmeldeinformationen für das Entwicklerportal.
Erstellen Sie ein persönliches Zugriffstoken, um auf die Repository-Funktionen zuzugreifen, zum Beispiel:

Speichern Sie das generierte Token in einer Umgebungsvariable namens MENDIX_TOKEN. Anweisungen hierzu finden Sie auf der Mendix PAT-Setup-Seite.
Nach Abschluss dieses Sie sollten jetzt bereit sein, die SDKs zu verwenden.
App zu JavaScript-Skript
Das Skript, das ich hier schreibe, ist ein nützliches Werkzeug, das Sie verwenden können, wenn Sie Mendix SDK-Arbeit.
Es wird das Modell von einem bestehenden Mendix App und suchen Sie ein Dokument im von Ihnen angegebenen Modell und geben Sie die Definition dieses Dokuments als JavaScript-Code aus.
Glauben Sie mir, wenn Sie anfangen zu arbeiten mit dem Mendix SDK: Sie werden dies wahrscheinlich immer wieder verwenden, da es nichts Besseres gibt, als sich ein vorhandenes Beispiel anzusehen, um Ihr Verständnis für die Verwendung des SDK und des Modells einer App zu verbessern.
Das Skript befindet sich auf Github und der Link zum Github-Projekt befindet sich unten am Ende dieses Blog-Beitrags.
Vorrunde
Das Skript öffnet sich und erwartet, dass die Befehlszeile einen Projektnamen (einen beliebigen Namen) und den qualifizierten Namen des Mendix Dokument (Mikroflow/Formular/Aufzählung) – dies ist also nur der Modulname, wenn Sie das Domänenmodell extrahieren möchten, oder der Modulname plus ein Punkt plus der Dokumentname. Wenn Sie zum ersten Mal auf ein anderes Projekt zugreifen, müssen Sie die App-ID zur Befehlszeile hinzufügen (aus der Registerkarte Allgemein auf der Mendix Entwicklerportalseite für die App) und einen Zweignamen, wenn Sie nicht den Standardzweig verwenden möchten.
import { JavaScriptSerializer } from "mendixmodelsdk";
import { MendixPlatformClient, OnlineWorkingCopy } from "mendixplatformsdk";
import * as fs from "fs";
// Usage: node showdocument.js nickname documentname appID branch
// nickname is your own name for the app
// documentname if the qualified name (module.document) of the document to serialize
// appID is the appID for the app (taken from the Mendix developer portal page)
// branch is the name of the branch to use
//
// The appID and branch are only needed when setting up a new working copy
//
// The appID, branch name and working copy ID are saved in a file called nickname.workingcopy in the
// current folder so they can be used next time if possible
//
const args = process.argv.slice(2);
async function main(args: string[])
{
var appID = "";
var branch = "";
var documentname = "";
if (args.length < 1)
{
console.log(`Need at least a nickname and document name on the command line`);
return;
}
const nickname = args[0].split(' ').join('');
documentname = args[1];
if (args.length > 2)
appID = args[2];
if (args.length > 3)
branch = args[3];
const workingCopyFile = nickname + '.workingcopy';
var wcFile;
var wcID;
try
{
wcFile = fs.readFileSync(workingCopyFile).toString();
appID = wcFile.split(':')[0];
branch = wcFile.split(':')[1];
wcID = wcFile.split(':')[2];
}
catch
{
wcFile = "";
wcID = "";
if (appID === "")
{
console.log("Need an appID on the command line if no workingcopy file is present for the nickname");
return;
}
}
Wenn das Skript ausgeführt wird, erstellt es eine Datei mit dem von Ihnen vergebenen Spitznamen + „.workingcopy“. Darin werden die App-ID, der Zweigname und die generierte Arbeitskopie-ID gespeichert. Dies ist so, dass beim nächsten Ausführen des Skripts für dieselbe App (Spitzname) die zuletzt erstellte Arbeitskopie-ID eingelesen und erneut verwendet wird. Dies beschleunigt den Vorgang erheblich.
const client = new MendixPlatformClient();
var workingCopy:OnlineWorkingCopy;
const app = client.getApp(appID);
var useBranch = branch;
if (wcID != "")
{
try
{
console.log("Opening existing working copy");
workingCopy = app.getOnlineWorkingCopy(wcID);
}
catch (e)
{
console.log(`Failed to get existing working copy ${wcID}: ${e}`);
wcID = ""
}
}
if (wcID === "")
{
const repository = app.getRepository();
if ((branch === "") || (branch === "trunk") || (branch === "main"))
{
const repositoryInfo = await repository.getInfo();
if (repositoryInfo.type === "svn")
useBranch = "trunk";
else
useBranch = "main";
}
try
{
workingCopy = await app.createTemporaryWorkingCopy(useBranch);
wcID = workingCopy.workingCopyId;
}
catch (e)
{
console.log(`Failed to create new working copy for app ${appID}, branch ${useBranch}: ${e}`);
return;
}
}
fs.writeFileSync(workingCopyFile, `${appID}:${useBranch}:${wcID}`);
Verwenden des SDK
Nachdem die Arbeitskopie erstellt/geöffnet wurde, öffnet das Skript nun das Modell für die App, findet das Domänenmodell oder das angegebene Dokument, ruft den JavaScript-Deserialisierer auf und schreibt die Ausgabe in die Konsole.
Beachten Sie, dass das Skript davon ausgeht, dass ein Dokumentname ohne Punkt ein Modulname ist und Sie das Domänenmodell für dieses Modul extrahieren möchten. Andernfalls wird der angegebene Name als qualifizierter Dokumentname (Modul.Dokument) betrachtet.
const model = await workingCopy!.openModel();
console.log(`Opening ${documentname}`);
if (documentname.split(".").length <= 1)
{
const domainmodelinterfaces = model.allDomainModels().filter(dm => dm.containerAsModule.name === documentname);
if (domainmodelinterfaces.length < 1)
console.log(`Cannot find domain model for ${document}`);
else
{
try
{
const domainmodelinterface = domainmodelinterfaces[0];
const domainmodel = await domainmodelinterface.load();
console.log(JavaScriptSerializer.serializeToJs(domainmodel));
}
catch(e)
{
console.log(`Error occured: ${e}`);
}
}
}
else
{
const documentinterfaces = model.allDocuments().filter(doc => doc.qualifiedName === documentname);
if (documentinterfaces.length < 1)
console.log(`Cannot find document for ${document}`);
else
{
try
{
const documentinterface = documentinterfaces[0];
const document = await documentinterface.load();
console.log(JavaScriptSerializer.serializeToJs(document));
}
catch(e)
{
console.log(`Error occured: ${e}`);
}
}
Beispiele
Bevor Sie das Skript ausführen oder nachdem Sie es geändert haben, sollten Sie es mit dem Befehl „tsc“ von TypeScript in JavaScript kompilieren. Dies funktioniert, sofern Sie den TypeScript-Dateinamen wie zuvor beschrieben in tsconfig.json aufgenommen haben.
tsc
Andernfalls können Sie eine bestimmte TypeScript-Datei mit einem Befehl wie dem folgenden kompilieren:
tsc showdocument.ts
Zuerst habe ich das Domänenmodell des Verwaltungsmodells mit dem folgenden Befehl heruntergeladen. Als Spitznamen für die App habe ich „Fred“ gewählt.
node showdocument.js fred Administration 8252db0e-6235-40a5-9502-36e324c618d7>/code>
Die Ausgabe kann sehr lang sein, daher werde ich nur einen Teil davon anzeigen.
var generalization1 = domainmodels.Generalization.create(model);
// Note: this is an unsupported internal property of the Model SDK which is subject to change.
generalization1.__generalization.updateWithRawValue("System.User");
var stringAttributeType1 = domainmodels.StringAttributeType.create(model);
var storedValue1 = domainmodels.StoredValue.create(model);
var fullName1 = domainmodels.Attribute.create(model);
fullName1.name = "FullName";
fullName1.type = stringAttributeType1; // Note: for this property a default value is defined.
fullName1.value = storedValue1; // Note: for this property a default value is defined.
var stringAttributeType2 = domainmodels.StringAttributeType.create(model);
var storedValue2 = domainmodels.StoredValue.create(model);
var email1 = domainmodels.Attribute.create(model);
email1.name = "Email";
email1.type = stringAttributeType2; // Note: for this property a default value is defined.
email1.value = storedValue2; // Note: for this property a default value is defined.
var booleanAttributeType1 = domainmodels.BooleanAttributeType.create(model);
var storedValue3 = domainmodels.StoredValue.create(model);
storedValue3.defaultValue = "true";
var isLocalUser1 = domainmodels.Attribute.create(model);
isLocalUser1.name = "IsLocalUser";
isLocalUser1.type = booleanAttributeType1; // Note: for this property a default value is defined.
isLocalUser1.value = storedValue3; // Note: for this property a default value is defined.
var memberAccess1 = domainmodels.MemberAccess.create(model);
memberAccess1.attribute = model.findAttributeByQualifiedName("Administration.Account.FullName");
memberAccess1.accessRights = domainmodels.MemberAccessRights.ReadWrite;
var memberAccess2 = domainmodels.MemberAccess.create(model);
memberAccess2.attribute = model.findAttributeByQualifiedName("Administration.Account.Email");
memberAccess2.accessRights = domainmodels.MemberAccessRights.ReadWrite;
var memberAccess3 = domainmodels.MemberAccess.create(model);
memberAccess3.attribute = model.findAttributeByQualifiedName("Administration.Account.IsLocalUser");
memberAccess3.accessRights = domainmodels.MemberAccessRights.ReadOnly;
var accessRule1 = domainmodels.AccessRule.create(model);
accessRule1.memberAccesses.push(memberAccess1);
accessRule1.memberAccesses.push(memberAccess2);
accessRule1.memberAccesses.push(memberAccess3);
accessRule1.moduleRoles.push(model.findModuleRoleByQualifiedName("Administration.Administrator"));
accessRule1.allowCreate = true;
accessRule1.allowDelete = true;
var memberAccess4 = domainmodels.MemberAccess.create(model);
memberAccess4.attribute = model.findAttributeByQualifiedName("Administration.Account.FullName");
memberAccess4.accessRights = domainmodels.MemberAccessRights.ReadOnly;
var memberAccess5 = domainmodels.MemberAccess.create(model);
memberAccess5.attribute = model.findAttributeByQualifiedName("Administration.Account.Email");
memberAccess5.accessRights = domainmodels.MemberAccessRights.ReadOnly;
var memberAccess6 = domainmodels.MemberAccess.create(model);
memberAccess6.attribute = model.findAttributeByQualifiedName("Administration.Account.IsLocalUser");
var accessRule2 = domainmodels.AccessRule.create(model);
accessRule2.memberAccesses.push(memberAccess4);
accessRule2.memberAccesses.push(memberAccess5);
accessRule2.memberAccesses.push(memberAccess6);
accessRule2.moduleRoles.push(model.findModuleRoleByQualifiedName("Administration.User"));
accessRule2.defaultMemberAccessRights = domainmodels.MemberAccessRights.ReadOnly;
var memberAccess7 = domainmodels.MemberAccess.create(model);
memberAccess7.attribute = model.findAttributeByQualifiedName("Administration.Account.FullName");
memberAccess7.accessRights = domainmodels.MemberAccessRights.ReadWrite;
var memberAccess8 = domainmodels.MemberAccess.create(model);
memberAccess8.attribute = model.findAttributeByQualifiedName("Administration.Account.Email");
var memberAccess9 = domainmodels.MemberAccess.create(model);
memberAccess9.attribute = model.findAttributeByQualifiedName("Administration.Account.IsLocalUser");
var accessRule3 = domainmodels.AccessRule.create(model);
accessRule3.memberAccesses.push(memberAccess7);
accessRule3.memberAccesses.push(memberAccess8);
accessRule3.memberAccesses.push(memberAccess9);
accessRule3.moduleRoles.push(model.findModuleRoleByQualifiedName("Administration.User"));
accessRule3.xPathConstraint = "[id='[%CurrentUser%]']";
var account1 = domainmodels.Entity.create(model);
account1.name = "Account";
account1.location = {"x":220,"y":140};
account1.generalization = generalization1; // Note: for this property a default value is defined.
account1.attributes.push(fullName1);
account1.attributes.push(email1);
account1.attributes.push(isLocalUser1);
account1.accessRules.push(accessRule1);
account1.accessRules.push(accessRule2);
account1.accessRules.push(accessRule3);
Dann habe ich den ChangeMyPassword-Mikroflow aus dem Modell heruntergezogen, indem ich den folgenden Befehl ausgeführt habe. Beachten Sie, dass keine App-ID erforderlich war, da die gerade erstellte vorhandene Arbeitskopie verwendet werden konnte.
node showdocument.js fred Administration.ChangeMyPassword
Diese Ausgabe ist sogar noch länger, daher werde ich erneut einen Teil der Ergebnisse ausschneiden.
var expressionSplitCondition1 = microflows.ExpressionSplitCondition.create(model);
expressionSplitCondition1.expression = "$AccountPasswordData/NewPassword = $AccountPasswordData/ConfirmPassword";
var exclusiveSplit1 = microflows.ExclusiveSplit.create(model);
exclusiveSplit1.relativeMiddlePoint = {"x":430,"y":200};
exclusiveSplit1.size = {"width":130,"height":80};
exclusiveSplit1.splitCondition = expressionSplitCondition1; // Note: for this property a default value is defined.
exclusiveSplit1.caption = "Passwords equal?";
var translation1 = texts.Translation.create(model);
translation1.languageCode = "en_US";
translation1.text = "The new passwords do not match.";
var translation2 = texts.Translation.create(model);
translation2.languageCode = "nl_NL";
translation2.text = "De nieuwe wachtwoorden komen niet overeen.";
var text1 = texts.Text.create(model);
text1.translations.push(translation1);
text1.translations.push(translation2);
var textTemplate1 = microflows.TextTemplate.create(model);
textTemplate1.text = text1; // Note: for this property a default value is defined.
var showMessageAction1 = microflows.ShowMessageAction.create(model);
showMessageAction1.template = textTemplate1; // Note: for this property a default value is defined.
showMessageAction1.type = microflows.ShowMessageType.Error;
var actionActivity1 = microflows.ActionActivity.create(model);
actionActivity1.relativeMiddlePoint = {"x":430,"y":75};
actionActivity1.size = {"width":120,"height":60};
actionActivity1.action = showMessageAction1;
var endEvent1 = microflows.EndEvent.create(model);
endEvent1.relativeMiddlePoint = {"x":430,"y":-20};
endEvent1.size = {"width":20,"height":20};
var startEvent1 = microflows.StartEvent.create(model);
startEvent1.relativeMiddlePoint = {"x":-220,"y":200};
startEvent1.size = {"width":20,"height":20};
var closeFormAction1 = microflows.CloseFormAction.create(model);
var actionActivity2 = microflows.ActionActivity.create(model);
actionActivity2.relativeMiddlePoint = {"x":1110,"y":200};
actionActivity2.size = {"width":120,"height":60};
actionActivity2.action = closeFormAction1;
var endEvent2 = microflows.EndEvent.create(model);
endEvent2.relativeMiddlePoint = {"x":1230,"y":200};
endEvent2.size = {"width":20,"height":20};
var memberChange1 = microflows.MemberChange.create(model);
// Note: this is an unsupported internal property of the Model SDK which is subject to change.
memberChange1.__attribute.updateWithRawValue("System.User.Password");
memberChange1.value = "$AccountPasswordData/NewPassword";
var changeObjectAction1 = microflows.ChangeObjectAction.create(model);
changeObjectAction1.items.push(memberChange1);
changeObjectAction1.refreshInClient = true;
changeObjectAction1.commit = microflows.CommitEnum.Yes;
changeObjectAction1.changeVariableName = "Account";
var actionActivity3 = microflows.ActionActivity.create(model);
actionActivity3.relativeMiddlePoint = {"x":620,"y":200};
actionActivity3.size = {"width":120,"height":60};
actionActivity3.action = changeObjectAction1;
actionActivity3.caption = "Save password";
actionActivity3.autoGenerateCaption = false;
var expressionSplitCondition2 = microflows.ExpressionSplitCondition.create(model);
expressionSplitCondition2.expression = "$OldPasswordOkay";
var exclusiveSplit2 = microflows.ExclusiveSplit.create(model);
exclusiveSplit2.relativeMiddlePoint = {"x":230,"y":200};
exclusiveSplit2.size = {"width":120,"height":80};
exclusiveSplit2.splitCondition = expressionSplitCondition2; // Note: for this property a default value is defined.
exclusiveSplit2.caption = "Old password okay?";
var endEvent3 = microflows.EndEvent.create(model);
endEvent3.relativeMiddlePoint = {"x":230,"y":-20};
endEvent3.size = {"width":20,"height":20};
var basicCodeActionParameterValue1 = microflows.BasicCodeActionParameterValue.create(model);
basicCodeActionParameterValue1.argument = "$Account/Name";
var javaActionParameterMapping1 = microflows.JavaActionParameterMapping.create(model);
// Note: this is an unsupported internal property of the Model SDK which is subject to change.
javaActionParameterMapping1.__parameter.updateWithRawValue("System.VerifyPassword.userName");
javaActionParameterMapping1.parameterValue = basicCodeActionParameterValue1; // Note: for this property a default value is defined.
var basicCodeActionParameterValue2 = microflows.BasicCodeActionParameterValue.create(model);
basicCodeActionParameterValue2.argument = "$AccountPasswordData/OldPassword";
var javaActionParameterMapping2 = microflows.JavaActionParameterMapping.create(model);
// Note: this is an unsupported internal property of the Model SDK which is subject to change.
javaActionParameterMapping2.__parameter.updateWithRawValue("System.VerifyPassword.password");
javaActionParameterMapping2.parameterValue = basicCodeActionParameterValue2; // Note: for this property a default value is defined.
OK, diese Snippets zeigen, dass die Ausgabe ziemlich umfangreich sein kann und sie geben möglicherweise Aufschluss über die Komplexität, die durch die Verwendung des SDK entstehen kann. Wenn Sie jedoch mit der Verwendung von JavaScript/TypeScript vertraut sind, werden Sie sich wahrscheinlich viel wohler fühlen.
Ähnliche Befehle können verwendet werden, um die Definitionen für die verschiedenen Dokumenttypen innerhalb eines Mendix app. Der JavaScriptSerializer kann Ihnen Code bereitstellen, der direkt (oder nach Änderung) zum Aktualisieren dieser oder einer anderen App verwendet werden kann, was äußerst nützlich ist. Aber…
Ein Hauch von Vorsicht
Die Verwendung des JavaScriptSerializers zum Herausziehen eines Teils Ihres Modells und dessen Konvertierung in JavaScript ist ideal, um Ihnen zu zeigen, wie Sie ähnliche Aktionen mit einem Modell durchführen könnten. Stimmt’s? Naja, fast.
Der generierte Code funktioniert fast immer, aber es gibt einige Aktionen, die nicht genau so wiedergegeben werden, wie Sie ein Skript zum Aktualisieren eines Modells schreiben müssen. Ich habe beispielsweise festgestellt, dass der generierte Code ist nicht ausführbar gegen ein Modell wobei das Skript die System Modul.
Das SDK ermöglicht keinen Zugriff auf die System Modul zum Lesen oder Schreiben, was eine Komplikation darstellt. Es gibt Workarounds, die es Ihnen ermöglichen, auf etwas im System Modul, so wird beispielsweise im Domänenmodell von Administration oben am Anfang des Skripts eine domainmodels.Generalization erstellt, die auf System.User verweist und später beim Erstellen der Spezialisierung namens Account am Ende des Skripts verwendet wird. Die im Skript angegebene Syntax ist korrekt, wird aber derzeit abgelehnt, wenn Sie versuchen, es auszuführen. Sie müssen Folgendes ersetzen:
generalization1.__generalization.updateWithRawValue("System.User");
mit:
(generalization1 as any)["_generalization"].updateWithRawValue("System.User");
Es gibt ähnliche Fälle beim Festlegen von Microflow-Aufrufparametern und beim Verweisen auf Attribute in System-Entitäten über Spezialisierungen. Ich gehe davon aus, dass es noch andere Stellen gibt, an denen diese Art von Problem auftreten kann. Diese Angelegenheiten stehen noch nicht fest, aber vorerst müssen Sie einen Workaround verwenden, wie den oben stehenden 👆.
Zusammenfassung
Ich hoffe, Sie finden diesen Blogbeitrag und das Skript nützlich. In meinem nächsten SDK-Beitrag Ich werde ein Skript schreiben, um eine brandneue App zu erstellen und ein Modul hinzuzufügen zusammen mit einem Domänenmodell und einigen einfachen Supportdokumenten.
Der Ordner und das Skript, die zur Erstellung dieses Blogbeitrags verwendet wurden, sowie die Ausgabe der Beispielbefehle sind verfügbar unter GitHub.