アプリの作成とモデルの構築
最初のSDKブログ投稿 TypeScriptスクリプトとNodeJSを使用してアクセスする方法を説明しました。 Mendix アプリモデルを作成し、モデルから情報をJavaScriptスクリプトにエクスポートします。次に、新しい Mendix プラットフォーム/モデル SDK スクリプトを使用してアプリを作成し、アプリ内に新しいモジュールを構築し、そのモジュールにいくつかの要素を配置します。

新しいアプリ
ブログの場合、ユースケースは非常にシンプルである必要があるため、非常に単純な注文入力シナリオを模倣したアプリを作成します。アプリには次のものが含まれます。
- 注文 ID、注文金額、注文ステータス、顧客名の自動番号を持つ注文エンティティ。受信した注文のドキュメント (PDF など) も保持できます。
- 注文明細 ID、製品名、明細値を持つ注文明細エンティティ。
- 注文と注文明細エンティティ間のカスケード削除との関連付け。
- ユーザーが入力した最大値と最小値の間の注文を検索するために使用される非永続エンティティ。
- 注文ステータスを表す列挙体。
- 管理者ロールと通常のユーザー ロールで構成された運用レベルのセキュリティ。実行方法を説明するために、永続エンティティを管理者には書き込み可能にし、通常のユーザーには読み取り専用にしました。
スクリプトはこれらすべてをゼロから構築し、 Mendix 作成されるアプリの基礎として使用されるバージョンと開始アプリ テンプレート。
今後のブログ投稿でこのアプリをさらに発展させていきたいと思います。
まず、すべてのアクティビティは main() と呼ばれる非同期関数で実行されます。これにより、await 修飾子を使用してコードを簡素化できます。
アプリを作成する
これは簡単で、アプリの名前とオプションの概要(説明)とテンプレートIDだけが必要です。テンプレートIDを指定しない場合は、最新の利用可能なデフォルトのテンプレートが使用されます。 Mendix バージョンが使用されます。
空のWebアプリテンプレートを使用します Mendix 9.18.1.
アプリで使用したいテンプレートのテンプレートIDは、 Mendix マーケットプレイスで「テンプレート」オプションを選択します。

必要なテンプレートをクリックし、テンプレートのページ内の「リリース」タブをクリックします。

個々のリリースを開くと、それぞれに関連する詳細が表示されます。これには、「Mendix 対象とする「バージョン」は異なります。 Mendix バージョンが表示されます。表示されていないバージョンを使用する必要がある場合は、必要なバージョンより前の最新のフレームワーク バージョンを選択し、アプリのビルド後に Studio Pro でアプリをアップグレードします。

使用したいリリースに対して指定されている UUID をコピーします。これは、createNewApp ステートメントに挿入できるテンプレート ID です。
import { MendixPlatformClient } from "mendixplatformsdk";
import { projects, security, domainmodels, enumerations, texts } from 'mendixmodelsdk';
main().catch(console.error);
async function main()
{
const client = new MendixPlatformClient();
// Create the app
const app = await client.createNewApp("SDKTestApp", {summary: "Test App created using the Mendix SDKs", templateId: "5cdf7b82-e902-4b8d-b0dd-bdd939c9e82f"});
console.log("App created with App ID: " + app.appId);
次に、アプリの作業コピーを作成し、モデルを開いて更新できるようにします。
// Open a working copy
const workingCopy = await app.createTemporaryWorkingCopy("trunk");
const model = await workingCopy.openModel();
モジュールを設定する
次に、新しいアプリ モジュールを作成し、任意の名前を付けて、モジュールのセキュリティを初期化します。このアプリでは、管理者アクセス用と一般ユーザー用の 2 つのロールを使用します。私が設定した方法は、SDK でセキュリティを設定する方法を示しただけなので、あまり現実的ではありません。管理者にはエンティティへの書き込みアクセス権が与えられ、一般ユーザーには読み取りアクセス権のみ与えられます (1 つの例外を除く)。
// Create a new module
const module = projects.Module.createIn(model.allProjects()[0]);
module.name = "SDKModule";
// Set up module security
const moduleSecurity = security.ModuleSecurity.createIn(module);
const adminRole = security.ModuleRole.createIn(moduleSecurity);
adminRole.name = "Admin";
const userRole = security.ModuleRole.createIn(moduleSecurity);
userRole.name = "User";
最後に、モジュールのドメイン モデルを作成し、その設定を開始する準備が整います。
S // Create the module domain model
const domainModel = domainmodels.DomainModel.createIn(module);
列挙を作成する
注文エンティティの「注文ステータス」は列挙型になるので、まずそれを作成し、次の 4 つの値を指定します。 New, 保留, 受講中, 完了簡単にするために、各値には米国英語のキャプションのみを提供します。
// Make the Order Status enumeration with its values
const statusEnumeration = enumerations.Enumeration.createIn(module);
statusEnumeration.name = "ENUM_Status";
const statusEnumerationValue1 = enumerations.EnumerationValue.createIn(statusEnumeration);
statusEnumerationValue1.name = "_New";
const statusEnumerationCaption1 = texts.Text.createInEnumerationValueUnderCaption(statusEnumerationValue1);
const statusEnumerationTranslation1 = texts.Translation.create(model);
statusEnumerationTranslation1.text = "New";
statusEnumerationTranslation1.languageCode = "en_US";
statusEnumerationCaption1.translations.push(statusEnumerationTranslation1);
const statusEnumerationValue2 = enumerations.EnumerationValue.createIn(statusEnumeration);
statusEnumerationValue2.name = "Hold";
const statusEnumerationCaption2 = texts.Text.createInEnumerationValueUnderCaption(statusEnumerationValue2);
const statusEnumerationTranslation2 = texts.Translation.create(model);
statusEnumerationTranslation2.text = "On Hold";
statusEnumerationTranslation2.languageCode = "en_US";
statusEnumerationCaption2.translations.push(statusEnumerationTranslation2);
const statusEnumerationValue3 = enumerations.EnumerationValue.createIn(statusEnumeration);
statusEnumerationValue3.name = "Progress";
const statusEnumerationCaption3 = texts.Text.createInEnumerationValueUnderCaption(statusEnumerationValue3);
const statusEnumerationTranslation3 = texts.Translation.create(model);
statusEnumerationTranslation3.text = "In Progress";
statusEnumerationTranslation3.languageCode = "en_US";
statusEnumerationCaption3.translations.push(statusEnumerationTranslation3);
const statusEnumerationValue4 = enumerations.EnumerationValue.createIn(statusEnumeration);
statusEnumerationValue4.name = "Completed";
const statusEnumerationCaption4 = texts.Text.createInEnumerationValueUnderCaption(statusEnumerationValue4);
const statusEnumerationTranslation4 = texts.Translation.create(model);
statusEnumerationTranslation4.text = "Completed";
statusEnumerationTranslation4.languageCode = "en_US";
statusEnumerationCaption4.translations.push(statusEnumerationTranslation4);
さて、これはかなり簡単なので、もう少し複雑なことに進みましょう。
エンティティを作成する
これを実行していくと、ここにあるコードと Studio Pro 内で同じアクションを実行することの間に明確な対応関係があることがわかるはずです。
まず、注文明細エンティティから始めましょう。エンティティの作成は簡単です。位置によって、Studio Pro ドメイン モデル ダイアグラム内でのエンティティの位置が決まります。x は、ダイアグラムの左から横に測ったダイアグラム ポイントの水平位置を指定し、y は、ダイアグラムの上から下に測ったダイアグラム ポイントの垂直位置を指定します。どちらも、エンティティ ボックスの左上隅を反映します。
// Create the Order Line Entity and attributes
const orderLineEntity = domainmodels.Entity.createIn(domainModel);
orderLineEntity.name = "OrderLine";
orderLineEntity.location = { x: 100, y: 100};
orderLineEntity.documentation = "The Order Line entity created using the Model SDK";
最初の 2 つの属性も単純です。1 つは整数で、もう 1 つは小数です。
const orderLineIdAttributeType = domainmodels.IntegerAttributeType.create(model);
const orderLineIdAttributeDefault = domainmodels.StoredValue.create(model);
orderLineIdAttributeDefault.defaultValue = "";
const orderLineIdAttribute = domainmodels.Attribute.createIn(orderLineEntity);
orderLineIdAttribute.name = "OrderLineId";
orderLineIdAttribute.type = orderLineIdAttributeType;
orderLineIdAttribute.value = orderLineIdAttributeDefault;
orderLineIdAttribute.documentation = "The Id of this Order Line unique within an order created using the Model SDK";
const orderLineValueAttributeType = domainmodels.DecimalAttributeType.create(model);
const orderLineValueAttributeDefault = domainmodels.StoredValue.create(model);
orderLineValueAttributeDefault.defaultValue = "";
const orderLineValueAttribute = domainmodels.Attribute.createIn(orderLineEntity);
orderLineValueAttribute.name = "OrderLineValue";
orderLineValueAttribute.type = orderLineValueAttributeType;
orderLineValueAttribute.value = orderLineValueAttributeDefault;
orderLineValueAttribute.documentation = "The Value of this Order Line created using the Model SDK";
3 番目の属性には、いくつかの特徴が追加されています。
- 属性は文字列であり、長さ (300) が指定されています。
- 属性には、空白ではないデフォルト値「Happy Days」があります。
- 属性には必須の検証ルールが適用されています。これにはエラー メッセージの定義が必要です。ここでも、簡潔にするために米国英語を使用します。
const orderLineProductNameAttributeType = domainmodels.StringAttributeType.create(model);
orderLineProductNameAttributeType.length = 300;
const orderLineProductNameAttributeDefault = domainmodels.StoredValue.create(model);
orderLineProductNameAttributeDefault.defaultValue = "Happy Days";
const orderLineProductNameAttribute = domainmodels.Attribute.createIn(orderLineEntity);
orderLineProductNameAttribute.name = "ProductName";
orderLineProductNameAttribute.type = orderLineProductNameAttributeType;
orderLineProductNameAttribute.value = orderLineProductNameAttributeDefault;
orderLineProductNameAttribute.documentation = "The name of the Product the subject of this Order Line created using the Model SDK";
const orderLineEntityValidationRule1 = domainmodels.ValidationRule.createIn(orderLineEntity);
orderLineEntityValidationRule1.attribute = orderLineProductNameAttribute;
domainmodels.RequiredRuleInfo.createIn(orderLineEntityValidationRule1);
const orderLineEntityValidationRuleText = texts.Text.createInValidationRuleUnderErrorMessage(orderLineEntityValidationRule1);
const orderLineEntityValidationRuleTranslation = texts.Translation.create(model);
orderLineEntityValidationRuleTranslation.text = "A Product Name must be entered";
orderLineEntityValidationRuleTranslation.languageCode = "en_US";
orderLineEntityValidationRuleText.translations.push(orderLineEntityValidationRuleTranslation);
次に、注文エンティティを作成します。これは、System.FileDocument の特殊化であるため、注文明細とは少し異なります。 SDK ブログ パート 1ただし、システム モジュール要素を使用するのは、セキュリティ上の理由から SDK スクリプト内で直接参照できないため、少し扱いにくいです。そのため、回避策を使用します。一般化エンティティがシステム モジュール内にない場合は、直接参照できます。
// Create the Order Entity and its attributes
const orderEntity = domainmodels.Entity.createIn(domainModel);
orderEntity.name = "Order";
orderEntity.location = { x: 500, y: 100};
orderEntity.documentation = "The Order Entity specializing from System.FileDocument created using the Model SDK";
const orderEntityGeneralization = domainmodels.Generalization.createIn(orderEntity);
(orderEntityGeneralization as any)["__generalization"].updateWithRawValue("System.FileDocument");
今のところ、注文エンティティの属性に対して特別な処理は行っていないため、コードは単純ですが、長さが指定された文字列属性 (100) があり、AutoNumber OrderId 属性に既定の開始値が定義され (「1」に設定)、OrderStatus (上記で作成した列挙体を使用) に既定値が設定されている (「_New」) ことに注意してください。
const orderIdAttributeType = domainmodels.AutoNumberAttributeType.create(model);
const orderIdAttributeDefault = domainmodels.StoredValue.create(model);
orderIdAttributeDefault.defaultValue = "1";
const orderIdAttribute = domainmodels.Attribute.createIn(orderEntity);
orderIdAttribute.name = "OrderId";
orderIdAttribute.type = orderIdAttributeType;
orderIdAttribute.value = orderIdAttributeDefault;
orderIdAttribute.documentation = "The Id of this Order Id unique accross the system created using the Model SDK";
const orderValueAttributeType = domainmodels.DecimalAttributeType.create(model);
const orderValueAttributeDefault = domainmodels.StoredValue.create(model);
orderValueAttributeDefault.defaultValue = "";
const orderValueAttribute = domainmodels.Attribute.createIn(orderEntity);
orderValueAttribute.name = "OrderValue";
orderValueAttribute.type = orderValueAttributeType;
orderValueAttribute.value = orderValueAttributeDefault;
orderValueAttribute.documentation = "The Value of this Order created using the Model SDK";
const customerNameAttributeType = domainmodels.StringAttributeType.create(model);
customerNameAttributeType.length = 100;
const customerNameAttributeDefault = domainmodels.StoredValue.create(model);
customerNameAttributeDefault.defaultValue = "";
const customerNameAttribute = domainmodels.Attribute.createIn(orderEntity);
customerNameAttribute.name = "CustomerName";
customerNameAttribute.type = customerNameAttributeType;
customerNameAttribute.value = customerNameAttributeDefault;
customerNameAttribute.documentation = "The name of the Customer who raised this Order created using the Model SDK";
const orderStatusAttributeType = domainmodels.EnumerationAttributeType.create(model);
orderStatusAttributeType.enumeration = statusEnumeration;
const orderStatusAttributeDefault = domainmodels.StoredValue.create(model);
orderStatusAttributeDefault.defaultValue = "_New";
const orderStatusAttribute = domainmodels.Attribute.createIn(orderEntity);
orderStatusAttribute.name = "OrderStatus";
orderStatusAttribute.type = orderStatusAttributeType;
orderStatusAttribute.value = orderStatusAttributeDefault;
orderStatusAttribute.documentation = "The status of this Order created using the Model SDK";
非永続的な OrderSearch エンティティとその属性を作成します。非永続性は単純なフラグを使用して設定されます。
// Create the OrderSearch non-persistent Entity
const orderSearchEntity = domainmodels.Entity.createIn(domainModel);
orderSearchEntity.name = "OrderSearch";
orderSearchEntity.location = { x: 900, y: 100};
orderSearchEntity.documentation = "A non-persistent entity used for searching Orders created using the Model SDK";
const orderSearchEntityNoGeneralization = domainmodels.NoGeneralization.createIn(orderSearchEntity);
orderSearchEntityNoGeneralization.persistable = false;
const orderSearchMinimumValueAttributeType = domainmodels.DecimalAttributeType.create(model);
const orderSearchMinimumValueDefaultValue = domainmodels.StoredValue.create(model);
orderSearchMinimumValueDefaultValue.defaultValue = "";
const orderSearchMiniumuValueAttribute = domainmodels.Attribute.createIn(orderSearchEntity);
orderSearchMiniumuValueAttribute.name = "MinimumValue";
orderSearchMiniumuValueAttribute.type = orderSearchMinimumValueAttributeType;
orderSearchMiniumuValueAttribute.value = orderSearchMinimumValueDefaultValue;
orderSearchMiniumuValueAttribute.documentation = "The search order value minimum value created using the Model SDK";
const orderSearchMaximumValueAttributeType = domainmodels.DecimalAttributeType.create(model);
const orderSearchMaximumValueDefaultValue = domainmodels.StoredValue.create(model);
orderSearchMaximumValueDefaultValue.defaultValue = "";
const orderSearchMaxiumuValueAttribute = domainmodels.Attribute.createIn(orderSearchEntity);
orderSearchMaxiumuValueAttribute.name = "MaximumValue";
orderSearchMaxiumuValueAttribute.type = orderSearchMaximumValueAttributeType;
orderSearchMaxiumuValueAttribute.value = orderSearchMaximumValueDefaultValue;
orderSearchMaxiumuValueAttribute.documentation = "The search order value maximum value created using the Model SDK";
最後に、注文と注文明細エンティティ間の関連付けを作成する必要があります。 子接続 (NAIST) と 親接続 設定はエンティティの設定と同様です 場所 値ですが、図の絶対位置ではなく、パーセンテージで表されます。 x 図中のエンティティの幅に沿ってどのくらい離れているかを示し、 y ダイアグラム内のエンティティの側面のどのくらい下かを示します。これらを使用すると、関連付けを表す線をエンティティ ボックス上の任意のポイントで終了するように設定できます。
関連付けが作成されると、注文オブジェクトが削除されたときに関連付けられた OrderLine オブジェクトも削除されるように削除動作が設定されます。
// Create the association between the OrderLine and Order Entities
const association = domainmodels.Association.createIn(domainModel);
association.name = "OrderLine_Order";
association.child = orderEntity;
association.parent = orderLineEntity;
association.type = domainmodels.AssociationType.Reference;
association.owner = domainmodels.AssociationOwner.Default;
association.childConnection = { x: 0, y: 50};
association.parentConnection = { x: 100, y: 50};
association.documentation = "Association created using the Model SDK";
const associationDeleteBehavior = domainmodels.AssociationDeleteBehavior.createIn(association);
associationDeleteBehavior.childDeleteBehavior = domainmodels.DeletingBehavior.DeleteMeAndReferences;
association.deleteBehavior = associationDeleteBehavior;
これらすべてをまとめると、次のようなドメイン モデル図が作成されます。

エンティティのセキュリティ設定
ここで、作成した管理者ロールとユーザー ロールのそれぞれについて、セキュリティを制御するための設定リストを実行する必要があります。各属性と関連付けは個別に設定する必要があります。ロールが異なる場合は、各ロールも個別に設定する必要があります。これは、かなり長くなりますが、比較的簡単です。
また、システム モジュールに直接アクセスできないため、以前と同様の回避策を使用して、System.FileDocument から継承された属性の設定を定義する必要があります。
// Set up the security on the new module's Entities
// Security settings for Order Line Entity for Admin user
const orderLineEntityAdminAccessRule = domainmodels.AccessRule.createInEntityUnderAccessRules(orderLineEntity);
orderLineEntityAdminAccessRule.allowCreate = true;
orderLineEntityAdminAccessRule.allowDelete = true;
orderLineEntityAdminAccessRule.defaultMemberAccessRights = domainmodels.MemberAccessRights.ReadWrite;
orderLineEntityAdminAccessRule.moduleRoles.push(adminRole);
const orderLineEntityAdminAccessOrderLineId = domainmodels.MemberAccess.createIn(orderLineEntityAdminAccessRule);
orderLineEntityAdminAccessOrderLineId.attribute = orderLineIdAttribute;
orderLineEntityAdminAccessOrderLineId.accessRights = domainmodels.MemberAccessRights.ReadWrite;
const orderLineEntityAdminAccessProductName = domainmodels.MemberAccess.createIn(orderLineEntityAdminAccessRule);
orderLineEntityAdminAccessProductName.attribute = orderLineProductNameAttribute;
orderLineEntityAdminAccessProductName.accessRights = domainmodels.MemberAccessRights.ReadWrite;
const orderLineEntityAdminAccessOrderLineValue = domainmodels.MemberAccess.createIn(orderLineEntityAdminAccessRule);
orderLineEntityAdminAccessOrderLineValue.attribute = orderLineValueAttribute;
orderLineEntityAdminAccessOrderLineValue.accessRights = domainmodels.MemberAccessRights.ReadWrite;
const orderLineEntityAdminAccessAssociation = domainmodels.MemberAccess.createIn(orderLineEntityAdminAccessRule);
orderLineEntityAdminAccessAssociation.association = association;
orderLineEntityAdminAccessAssociation.accessRights = domainmodels.MemberAccessRights.ReadWrite;
// Security settings for Order Line Entity for regular user
const orderLineEntityUserAccessRule = domainmodels.AccessRule.createInEntityUnderAccessRules(orderLineEntity);
orderLineEntityUserAccessRule.allowCreate = false;
orderLineEntityUserAccessRule.allowDelete = false;
orderLineEntityUserAccessRule.defaultMemberAccessRights = domainmodels.MemberAccessRights.ReadOnly;
orderLineEntityUserAccessRule.moduleRoles.push(userRole);
const orderLineEntityUserAccessOrderLineId = domainmodels.MemberAccess.createIn(orderLineEntityUserAccessRule);
orderLineEntityUserAccessOrderLineId.attribute = orderLineIdAttribute;
orderLineEntityUserAccessOrderLineId.accessRights = domainmodels.MemberAccessRights.ReadOnly;
const orderLineEntityUserAccessProductName = domainmodels.MemberAccess.createIn(orderLineEntityUserAccessRule);
orderLineEntityUserAccessProductName.attribute = orderLineProductNameAttribute;
orderLineEntityUserAccessProductName.accessRights = domainmodels.MemberAccessRights.ReadOnly;
const orderLineEntityUserAccessOrderLineValue = domainmodels.MemberAccess.createIn(orderLineEntityUserAccessRule);
orderLineEntityUserAccessOrderLineValue.attribute = orderLineValueAttribute;
orderLineEntityUserAccessOrderLineValue.accessRights = domainmodels.MemberAccessRights.ReadOnly;
const orderLineEntityUserAccessAssociation = domainmodels.MemberAccess.createIn(orderLineEntityUserAccessRule);
orderLineEntityUserAccessAssociation.association = association;
orderLineEntityUserAccessAssociation.accessRights = domainmodels.MemberAccessRights.ReadOnly;
// Security settings for Order Entity for Admin user
const orderEntityAdminAccessRule = domainmodels.AccessRule.createInEntityUnderAccessRules(orderEntity);
orderEntityAdminAccessRule.allowCreate = true;
orderEntityAdminAccessRule.allowDelete = true;
orderEntityAdminAccessRule.defaultMemberAccessRights = domainmodels.MemberAccessRights.ReadWrite;
orderEntityAdminAccessRule.moduleRoles.push(adminRole);
const orderEntityAdminAccessOrderId = domainmodels.MemberAccess.createIn(orderEntityAdminAccessRule);
orderEntityAdminAccessOrderId.attribute = orderIdAttribute;
orderEntityAdminAccessOrderId.accessRights = domainmodels.MemberAccessRights.ReadOnly;
const orderEntityAdminAccessOrderValue = domainmodels.MemberAccess.createIn(orderEntityAdminAccessRule);
orderEntityAdminAccessOrderValue.attribute = orderValueAttribute;
orderEntityAdminAccessOrderValue.accessRights = domainmodels.MemberAccessRights.ReadWrite;
const orderEntityAdminAccessCustomerName = domainmodels.MemberAccess.createIn(orderEntityAdminAccessRule);
orderEntityAdminAccessCustomerName.attribute = customerNameAttribute;
orderEntityAdminAccessCustomerName.accessRights = domainmodels.MemberAccessRights.ReadWrite;
const orderEntityAdminAccessOrderStatus = domainmodels.MemberAccess.createIn(orderEntityAdminAccessRule);
orderEntityAdminAccessOrderStatus.attribute = orderStatusAttribute;
orderEntityAdminAccessOrderStatus.accessRights = domainmodels.MemberAccessRights.ReadWrite;
const orderEntityAdminAccessName = domainmodels.MemberAccess.createIn(orderEntityAdminAccessRule);
(orderEntityAdminAccessName as any)["__attribute"].updateWithRawValue("System.FileDocument.Name");
orderEntityAdminAccessName.accessRights = domainmodels.MemberAccessRights.ReadWrite;
const orderEntityAdminAccessFileId = domainmodels.MemberAccess.createIn(orderEntityAdminAccessRule);
(orderEntityAdminAccessFileId as any)["__attribute"].updateWithRawValue("System.FileDocument.FileID");
orderEntityAdminAccessFileId.accessRights = domainmodels.MemberAccessRights.ReadOnly;
const orderEntityAdminAccessDeleteAfterDownload = domainmodels.MemberAccess.createIn(orderEntityAdminAccessRule);
(orderEntityAdminAccessDeleteAfterDownload as any)["__attribute"].updateWithRawValue("System.FileDocument.DeleteAfterDownload");
orderEntityAdminAccessDeleteAfterDownload.accessRights = domainmodels.MemberAccessRights.ReadWrite;
const orderEntityAdminAccessContents = domainmodels.MemberAccess.createIn(orderEntityAdminAccessRule);
(orderEntityAdminAccessContents as any)["__attribute"].updateWithRawValue("System.FileDocument.Contents");
orderEntityAdminAccessContents.accessRights = domainmodels.MemberAccessRights.ReadWrite;
const orderEntityAdminAccessHasContents = domainmodels.MemberAccess.createIn(orderEntityAdminAccessRule);
(orderEntityAdminAccessHasContents as any)["__attribute"].updateWithRawValue("System.FileDocument.HasContents");
orderEntityAdminAccessHasContents.accessRights = domainmodels.MemberAccessRights.ReadOnly;
const orderEntityAdminAccessSize = domainmodels.MemberAccess.createIn(orderEntityAdminAccessRule);
(orderEntityAdminAccessSize as any)["__attribute"].updateWithRawValue("System.FileDocument.Size");
orderEntityAdminAccessSize.accessRights = domainmodels.MemberAccessRights.ReadOnly;
// Security settings for Order Entity for regular user
const orderEntityUserAccessRule = domainmodels.AccessRule.createInEntityUnderAccessRules(orderEntity);
orderEntityUserAccessRule.allowCreate = false;
orderEntityUserAccessRule.allowDelete = false;
orderEntityUserAccessRule.defaultMemberAccessRights = domainmodels.MemberAccessRights.ReadOnly;
orderEntityUserAccessRule.moduleRoles.push(userRole);
const orderEntityUserAccessOrderId = domainmodels.MemberAccess.createIn(orderEntityUserAccessRule);
orderEntityUserAccessOrderId.attribute = orderIdAttribute;
orderEntityUserAccessOrderId.accessRights = domainmodels.MemberAccessRights.ReadOnly;
const orderEntityUserAccessOrderValue = domainmodels.MemberAccess.createIn(orderEntityUserAccessRule);
orderEntityUserAccessOrderValue.attribute = orderValueAttribute;
orderEntityUserAccessOrderValue.accessRights = domainmodels.MemberAccessRights.ReadOnly;
const orderEntityUserAccesCustomerName = domainmodels.MemberAccess.createIn(orderEntityUserAccessRule);
orderEntityUserAccesCustomerName.attribute = customerNameAttribute;
orderEntityUserAccesCustomerName.accessRights = domainmodels.MemberAccessRights.ReadOnly;
const orderEntityUserAccesOrderStatus = domainmodels.MemberAccess.createIn(orderEntityUserAccessRule);
orderEntityUserAccesOrderStatus.attribute = orderStatusAttribute;
orderEntityUserAccesOrderStatus.accessRights = domainmodels.MemberAccessRights.ReadOnly;
const orderEntityUserAccessName = domainmodels.MemberAccess.createIn(orderEntityUserAccessRule);
(orderEntityUserAccessName as any)["__attribute"].updateWithRawValue("System.FileDocument.Name");
orderEntityUserAccessName.accessRights = domainmodels.MemberAccessRights.ReadOnly;
const orderEntityUserAccessFileId = domainmodels.MemberAccess.createIn(orderEntityUserAccessRule);
(orderEntityUserAccessFileId as any)["__attribute"].updateWithRawValue("System.FileDocument.FileID");
orderEntityUserAccessFileId.accessRights = domainmodels.MemberAccessRights.ReadOnly;
const orderEntityUserAccessDeleteAfterDownload = domainmodels.MemberAccess.createIn(orderEntityUserAccessRule);
(orderEntityUserAccessDeleteAfterDownload as any)["__attribute"].updateWithRawValue("System.FileDocument.DeleteAfterDownload");
orderEntityUserAccessDeleteAfterDownload.accessRights = domainmodels.MemberAccessRights.ReadOnly;
const orderEntityUserAccessContents = domainmodels.MemberAccess.createIn(orderEntityUserAccessRule);
(orderEntityUserAccessContents as any)["__attribute"].updateWithRawValue("System.FileDocument.Contents");
orderEntityUserAccessContents.accessRights = domainmodels.MemberAccessRights.ReadOnly;
const orderEntityUserAccessHasContents = domainmodels.MemberAccess.createIn(orderEntityUserAccessRule);
(orderEntityUserAccessHasContents as any)["__attribute"].updateWithRawValue("System.FileDocument.HasContents");
orderEntityUserAccessHasContents.accessRights = domainmodels.MemberAccessRights.ReadOnly;
const orderEntityUserAccessSize = domainmodels.MemberAccess.createIn(orderEntityUserAccessRule);
(orderEntityUserAccessSize as any)["__attribute"].updateWithRawValue("System.FileDocument.Size");
orderEntityUserAccessSize.accessRights = domainmodels.MemberAccessRights.ReadOnly;
// Security settings for OrderSearch Entity for both Admin and regular users
const orderSearchEntityUserAccessRule = domainmodels.AccessRule.createInEntityUnderAccessRules(orderSearchEntity);
orderSearchEntityUserAccessRule.allowCreate = true;
orderSearchEntityUserAccessRule.allowDelete = true;
orderSearchEntityUserAccessRule.defaultMemberAccessRights = domainmodels.MemberAccessRights.ReadWrite;
orderSearchEntityUserAccessRule.moduleRoles.push(adminRole);
orderSearchEntityUserAccessRule.moduleRoles.push(userRole);
const orderSearchEntityUserAccessMinimumValue = domainmodels.MemberAccess.createIn(orderSearchEntityUserAccessRule);
orderSearchEntityUserAccessMinimumValue.attribute = orderSearchMiniumuValueAttribute;
orderSearchEntityUserAccessMinimumValue.accessRights = domainmodels.MemberAccessRights.ReadWrite;
const orderSearchEntityUserAccessMaximumValue = domainmodels.MemberAccess.createIn(orderSearchEntityUserAccessRule);
orderSearchEntityUserAccessMaximumValue.attribute = orderSearchMaxiumuValueAttribute;
orderSearchEntityUserAccessMaximumValue.accessRights = domainmodels.MemberAccessRights.ReadWrite;e
完成
もうすぐ終わりです!次に、プロジェクトを「本番」(すべてをチェック)セキュリティ レベルに設定し、先ほど作成したモジュール ロールを取得してプロジェクト ロールにマップします。
次に、変更をフラッシュしてコミットします。
// Set up the project level security roles. Set Production level security and put the module roles into the project roles
const projectSecurity = await model.allProjectSecurities()[0].load();
projectSecurity.securityLevel = security.SecurityLevel.CheckEverything;
projectSecurity.checkSecurity = true;
const adminRoleName = projectSecurity.adminUserRoleName;
const projectAdminRole = projectSecurity.userRoles.find(t => t.name === adminRoleName);
const projectUserRole = projectSecurity.userRoles.find(t => t.name === "User");
if (projectAdminRole != undefined)
projectAdminRole.moduleRoles.push(adminRole);
if (projectUserRole != undefined)
projectUserRole.moduleRoles.push(userRole);
console.log("Committing changes to the repository");
await model.flushChanges();
await workingCopy.commitToRepository("trunk", {commitMessage: "App created and modified by my Create App Model SDK script"});
}
このスクリプトをNodeJS初期化フォルダに保存すると( SDK ブログ 1 方法については、TypeScriptファイル(私は「createapp.ts」と名付けました)として参照してください。これで、TypeScriptをJavaScriptにコンパイルできます。 TSC 生成された JavaScript を実行するには node を使用します。
このスクリプトを実行すると、追加されたモジュールと入力されたドメイン モデルを使用してアプリが作成されます。まだ、それほど多くの機能はありませんが、このブログ シリーズのパート 3 で、詳細を説明していきます。

Errors
SDK を使用してアプリを更新するときの経験から生まれた警告の言葉です。SDK システムは、必ずしも間違いを報告するわけではありません。間違いを犯した場合、プロセスのさまざまな時点でその事実を知ることができます。
- TypeScript コンパイラは、JavaScript にコンパイルするときに問題を報告します。
- node を使用して JavaScript を実行すると、問題が報告されます。
- Studio Pro でアプリを開くと、エラー タブにエラーや問題が報告されたり、作成または変更した内容が間違って表示される場合があります。
- 状況が本当に悪い場合、Studio Pro は起動中に例外を報告したり、アプリをまったく開けずに動作しなくなる可能性があります。
このことから私はこう言いたい。 常に代替案を用意しておく既存のプロジェクトの場合は、プロジェクトのバックアップ コピーを作成します。プロジェクトをコピーして、コピーで作業します。ブランチで作業します。おそらくこれらすべて...

私の言う通りにしなさい、私の行動通りにしてはいけない
経験豊富な開発者の多くは、おそらく上記のコードを見てうんざりしているでしょう。これらのスクリプトが非常に長くて繰り返しになる可能性があることは明らかです (たとえば、ドメイン モデルの変更は、フォームやマイクロフローの設定と比較すると簡単です)。しかし、私は、特にブログ投稿の場合は、合理的な範囲で物事をできるだけ明確にしたいと思っています。これには、意味のある変数名を使用し、複雑な構文を避けることが含まれます。
最初にできることは、スクリプトを短くするのに役立つ関数を使用することです。たとえば、次のようになります。
createEnumerationOption(model, statusEnumeration, "_New", "New");
createEnumerationOption(model, statusEnumeration, "Hold", "On Hold");
createEnumerationOption(model, statusEnumeration, "Progress", "In Progress");
createEnumerationOption(model, statusEnumeration, "Completed", "Completed");
.....
function createEnumerationOption(model: IModel, enumeration: enumerations.Enumeration, name: string, caption_en_US: string)
{
const value = enumerations.EnumerationValue.createIn(enumeration);
value.name = name;
const caption = texts.Text.createInEnumerationValueUnderCaption(value);
const translation = texts.Translation.create(model);
translation.text = caption_en_US;
translation.languageCode = "en_US";
caption.translations.push(translation);
}
おそらく、作成するさまざまな SDK スクリプトに含めて使用できる関数やクラスのライブラリを構築する価値がわかるでしょう。
しかし、長いスクリプトは他の理由でパフォーマンスの問題に直面する可能性もあります。メモリのオーバーヘッドを減らして速度を向上させるために私が学んだ 3 つのことは次のとおりです。
- FlushChangesを頻繁に呼び出します。これにより、これまでに行った変更がローカルのNodeJS環境から Mendix ModelServer はローカル メモリのフットプリントを削減します。
- 可能な場合は、ローカル スコープの変数を使用します。関数を使用すると、これが簡単に行えます。ローカル スコープの変数は、定義したブロック内で生成、実行、終了するため、スクリプトの残りの部分で持ち運ばれるデータの蓄積が減ります。スクリプト内の各変数参照には、JavaScript 内部での何らかの検索が必要であり、定義した変数の数が多いほど、かかる時間が長くなります (メモリの消費量も多くなります)。
- 変数名は短く、少なくとも短くしてください。これにより、実行時間が短縮され、長いスクリプトのメモリ オーバーヘッドが削減されます。明らかに、簡潔さと明瞭さの間にはトレードオフがあります。私は、TypeScript ファイルを書き込んでアプリを変更するアプリを持っていますが、スイッチを切り替えるだけで、意味のある変数名 (デバッグ用) または短い変数名 (本番環境用) を生成するように設定できます。または、別のツールを使用して、生成された JavaScript を実行する前に縮小することもできますが、これは試したことがないため、どの程度うまく機能するかはわかりません。
下記の Github リポジトリには、このブログで紹介した単純なスクリプト (「createapp.ts」) と、ここで提案した変更の一部を実装した代替スクリプト (「createapp2.ts」) の XNUMX つのスクリプトが含まれています。各スクリプトは同じアプリを生成しますが、XNUMX 番目のスクリプトの方が大幅に短く、理解しやすいと思います。
これでこの投稿は終わりです。スクリプトはGithubで入手できます。 https://github.com/Adrian-Preston/SDKBlog2.
パート 3 では引き続き機能の開発を進めていきます。近日公開予定です。