大きな変化の一つは Mendix 7ではステートレスランタイムが導入され、状態がランタイムからクライアントに移されました。 Mendix 7 では、クライアントは状態を追跡し、ブラウザとモバイル アプリの両方のリクエストとともにランタイムに送信するようになりました。この機能により、ランタイムは水平方向に拡張でき、アプリケーションがより多くのサーバー リソースを必要とする場合に非常に柔軟に機能します。
このブログシリーズのパート 1 では、アプリを詳しく見て、各ステップで状態の観点から何が起こっているかを示し、クライアントの状態がどのように機能するかをより深く理解できるようにします。
免責事項:このブログ投稿は Mendix 7.23.1. 状態の動作は以前のリリースと異なる場合があり、今後のリリースでは予告なく変更される可能性があります。
国家とは何か、そして国家には実際に何が含まれているのか?
ユーザーとして Mendix アプリでは、操作するデータの一部がまだデータベースに保存されていない可能性があります。正確には、状態は次のもので構成されます。
- 新しく作成され、まだコミットされていないすべての永続化オブジェクト (PE)
- すべての永続不可能なオブジェクト (NPE)
- オブジェクトに対して行われたすべての属性と関連付けの変更 (関連付けと属性はクライアントでは同じように扱われるため、この投稿の残りの部分では関連付けについては説明しません)
これらのオブジェクトと変更が状態を構成します。これらはまだアプリのデータベースに保存されていないため、データベースに保存されるか、破棄されるか、アプリで不要になるまで、状態に保存する必要があります。
状態の変更はさまざまな方法で導入できます。
- 新しいオブジェクトは、ランタイムのマイクロフロー、クライアントのナノフロー、またはオブジェクトの作成クライアントアクションによって作成できます。
- 属性の変更は、マイクロフロー、ナノフロー、カスタムウィジェット、またはエンドユーザーによって行うことができます。
状態の観点からは、オブジェクトまたは変更のソースは重要ではありません。すべてのオブジェクトと変更は、クライアントの状態になります。
状態には、前述のものより多くのオブジェクトが含まれる場合があります。状態にはコミットされたオブジェクトが含まれる場合もあります。これは、アプリのパフォーマンスを向上させるためによく行われます。
変更とは何ですか? また、変更は状態にどのように保存されますか?
変更はコミットされていない値を参照します Mendix オブジェクトの属性。たとえば、ユーザーがテキストボックスを使用して属性の値を変更すると、 Mendix 新しい値は編集されたオブジェクトの状態の変化として保存されます。 Mendix オブジェクト自体はまだ変更されていません。
変更を分離しておく Mendix オブジェクトをロールバックするたびに、 Mendix マイクロフロー、ナノフロー、またはキャンセル変更クライアントアクション内のオブジェクト、 Mendix 状態内のオブジェクトに対して行われたすべての変更を破棄するだけです。
つまり、ユーザーが保存ボタンをクリックするたびに、 Mendix 編集されたオブジェクトに加えられたすべての変更を収集して送信し、それらの変更をランタイムのデータベースに保存できるようにします。これは、マイクロフロー呼び出しなど、変更されたオブジェクトを必要とする他のランタイム要求にも当てはまります。
国家の範囲
自律的AI Mendix 7、状態はブラウザのメモリに保存されます。 Mendix クライアント。つまり、Web アプリの場合、状態は現在のブラウザー タブにローカルです。別のタブでアプリを開いた場合、前のタブの状態にアクセスすることはできません。また、現在のブラウザー タブを更新すると、その状態が失われることになります。
最後のケースには例外が1つあります。 Mendix クライアントはあなたの状態を セッションストレージ 高速デプロイ機能を利用するには、ブラウザを一時的に閉じる必要があります。これにより、モデルに変更を加えたときのページまたは状態からアプリ内で作業を続行し、それを実行できます。この機能は開発中にのみ使用できます。
上記の両方の動作は、 Mendix 7に組み込まれているアプリとは互換性がありません Mendix 6以前では Mendix 6 では、状態は引き続き別のタブからアクセス可能であり、更新されても保持されます。
国家と安全保障
クライアントに状態を保存すると、セキュリティに影響が及びます。
現在のユーザーの読み取り専用属性 Mendix 現在のユーザーの読み取り専用属性値は、その値の横にハッシュを付けて保護されるため、それらの値を不正に変更しようとする試みはすべて検出され、拒否されます。
現在のユーザーがアクセスできない属性の変更 ログインしたユーザーがアクセスできない属性の変更は状態に保存できません。クライアントに送信すると機密データが漏洩するリスクがあるため、このような変更は破棄されます。
状態はランタイムにどのように伝達されますか?
その Mendix クライアントは特別なエンドポイントを介してランタイムと通信します /xasたとえば、データグリッドのデータをロードするときやマイクロフローを呼び出すときなどです。このAPIの各タイプの呼び出しはアクションと呼ばれ、必要な状態の部分がそれとともに送信されます。 xas リクエスト ネットワーク ブラウザの開発者ツールのタブを開き、 xas パス。訪問します xas APIについては後ほど記事で説明します。
お断り: xas は、 Mendix クライアントとランタイムに関するものであり、今後のリリースでは予告なく変更される可能性があります。ここで提供される詳細は、 Mendix アプリはランタイムと通信するため、より優れたアプリをモデル化し、アプリの問題をより効果的にトラブルシューティングできます。
いつでも xas アクション(マイクロフロー呼び出しなど)がトリガーされ、 Mendix クライアントも状態を送信します。 Mendix パフォーマンス上の大きな問題が発生するため、クライアントは状態全体をランタイムに送信しません。 Mendix アプリケーションの展開中に各マイクロフローを分析して、状態のどの部分を送信するかを決定します。
クライアントの状態を検査できますか?
押します Ctrlキー+他の+G キーの組み合わせにより、その時点でのクライアント状態の概要がブラウザ コンソールにダンプされるため、保存されている内容を調べることができます。このショートカットを使用して、サンプル アプリを調べます。
アート作品登録アプリ
クライアントの状態を示すために、アーティストに関する情報を保存できるシンプルなアートワーク レジストリ アプリを構築しました。
プロジェクトをダウンロードできます こちら そして、その状態を調べながら進めていきます。
これが私たちのシンプルなドメインモデルです。 アーティスト エンティティを持つ フルネーム 属性。
アプリを実行してみましょう。ホームページは意図的に空にしているので、 Mendix クライアントは空の状態から開始します。

これを確認するには、 領事 開発者ツールで Ctrl + Alt + G ショートカット。

ここでは、状態が JSON オブジェクトとして表現されていますが、現在は空であることがわかります。
クリック アーティスト メニュー項目。ここには、アプリで定義されているすべてのアーティストのリスト ビューがあります。現在はアーティストは存在しません。

をクリックして新しいアーティストを作成します 新しいアーティストを作成 ボタンを押して、何が起こるかを調べてください ネットワーク 開発者ツールのタブで最初のリクエストを選択します xas/ パスをスクロールダウンして ヘッダ 詳細ビューのタブ:

リクエストペイロードを抽出して検査します。
Switch to "Text" tab and paste code here
上の画像は典型的な xas リクエスト。各フィールドを確認してみましょう。
action: 全てのランタイム操作はxasAPIなので、各操作を区別できる必要があります。ここではactionフィールドはこの目的に適う。現在のアクションはinstantiateランタイムに作成を依頼する Mendix オブジェクト。params:それぞれxasアクションには独自のパラメータセットがあるかもしれないので、paramsアクション固有のパラメータが含まれます。instantiate呼び出し時に、ランタイムは作成するオブジェクトのタイプを知る必要があるため、objecttypeフィールド。changes: これはクライアントの状態に関連するフィールドの1つです。xasリクエストが行われた場合、 Mendix クライアントはリクエストに関連する状態を送信し、changesその状態の一部です。新しいオブジェクトの作成には状態は必要ないため、ここでは空です。objects: これはクライアントの状態に関連する2番目のフィールドです。ここでは Mendix クライアントは、リクエスト中にランタイムが必要とする可能性のある状態からオブジェクトを提供します。新しいオブジェクトの作成にはオブジェクトの状態は必要ないため、これも空です。
応答を確認するには、 プレビュー 内のタブ ネットワーク リクエストの詳細ビュー:

詳細を調べる際には、開発者ツールのスクリーンショットを省略し、抽出したバージョンのみを表示します。
{
"actionResult": "5629499534213124",
"commits": [],
"changes": {},
"resets": {},
"deletes": [],
"newpersistable": [
"5629499534213124"
],
"objects": [
{
"objectType": "MyFirstModule.Artist",
"guid": "5629499534213124",
"hash": "Nw09VTjCQKib7DbE5Agxgm3Bg6fEGL4mPRyNrgiUKGs=",
"attributes": {
"FullName": {
"value": null
}
}
}
]
}
上の画像は典型的な xas 応答。 actionResult フィールドはアクション自体に直接関連していますが、他のフィールドはクライアントの状態に関連しています。
各電話の後に xasランタイム応答には、どのオブジェクトが作成または削除されたかなど、リクエスト中に発生した事象に関する情報が保持されます。ランタイムは各応答でそれらの情報をクライアントに伝えるため、クライアントはそれらの変更を状態に適用します。
クライアントの状態に関連する応答フィールドの概要は次のとおりです。
コミット
このフィールドには、リクエスト中にコミットされた GUID のリストが含まれます。作成自体ではオブジェクトはコミットされないため、空になります。入力すると次のようになります。
"commits": ["guid_1", "guid_2", "...guid_n"]
その Mendix クライアントはこの情報を使用して、新しいオブジェクトがいつコミットされたかを認識します。これにより、クライアントの状態を適宜更新できます。
変更
このフィールドには、 Mendix リクエスト中に作成されたオブジェクト。つまり、これらの変更はまだコミットされていないため、状態に保存する必要があります。
このフィールドは、 instantiate 新しいバージョンには変更がないため、 Artist まだ反対している。しかし、 Artist オブジェクトに After Create イベント マイクロフローがあり、アーティストの名前をデフォルト値に変更した場合、そのフィールドは次のようになります。
"changes": {
"5629499534213124": {
"FullName": {
"value": "Value set in the event microflow"
}
}
}
その Mendix クライアントはここで変更を受け取り、それをクライアントの状態に適用します。
リセット
このフィールドには、各ロールバックされた属性変更の概要が含まれます。 Mendix オブジェクト。 Mendix クライアントはその情報を使用して、その状態から既存の変更を削除します。リセットの例を次に示します。
"resets": {
"guid_of_the_object": ["attribute_1", "attribute_2"]
}
削除
このフィールドには、次のGUIDのリストが含まれます。 Mendix リクエスト中に削除されたオブジェクト。 Mendix クライアントは、その削除情報を使用して、対応するオブジェクトとその変更を状態から削除します。上記のリクエストの例ではこのフィールドは空ですが、削除の例を次に示します。
"deletes": ["guid_1", "guid_2", "...guid_n"]
新しい永続性
このフィールドにはリクエスト中に作成されたGUIDのリストが含まれているため、 Mendix クライアントは、まだコミットされていないことを知っており、必要なだけ保存する必要があります。 instantiate 呼び出しにより、新しい Artist オブジェクトは作成されましたが、コミットされていません。そのため、その GUID がこのフィールドの一部であることがわかります。
オブジェクト
このフィールドには、 Mendix ランタイムアクションがレスポンスの一部としてクライアントに送信する必要のあるオブジェクト。この例では、ランタイムは新しい Artist オブジェクト。
典型的な Mendix オブジェクトには次のフィールドが含まれます。
objectType: オブジェクトのオブジェクト タイプを定義します。guid: オブジェクトの一意の ID。hash: これにより、オブジェクト全体のコンテンツが改ざんされないことが保証されます。attributes: には、 コミットした オブジェクトの各属性の値。新しいオブジェクトの場合、これらの値は属性のデフォルト値と同じです。現在のユーザーがアクセスできる属性のみが存在することに注意してください。
この短い紹介の後、デモアプリケーションに戻りましょう。 xas リクエストとレスポンス。
新しいボタンをクリックすると、「アーティスト」エンティティの新しいインスタンスが作成され、 Mendix クライアントは新しいオブジェクトを含む詳細ページを表示します。

ここで、状態検査のショートカット(Ctrlキー+他の+G) をクリックしてクライアントの状態を確認します。
{
"MyFirstModule.Artist": {
"5629499534213124 (new)": {
"subscribedWidgets": [
"MyFirstModule.Artist_NewEdit.dataView1",
"MyFirstModule.Artist_NewEdit.textBox1",
null
]
}
}
}
クライアント国は今、新たな Mendix オブジェクトであり、それを (new) guidの後にプレフィックスが付いており、まだコミットされていないことを示しています。また、 subscribedWidgets フィールドは、そのオブジェクトを使用するウィジェットを示します。これが、このオブジェクトが状態に保持される理由です。最後のエントリは nullつまり、ページ上または Mendix オブジェクトを使用するが、説明を持たないクライアント自体。
新しいアーティストの名前を Pablo Picasso状態を再度検査します。
{
"MyFirstModule.Artist": {
"5629499534213124 (new)": {
"changes": {
"FullName": {
"value": "Pablo Picasso"
}
},
"subscribedWidgets": [
"MyFirstModule.Artist_NewEdit.dataView1",
"MyFirstModule.Artist_NewEdit.textBox1",
null
]
}
}
}
}
今回は、追加の changes オブジェクトのフィールドで、変更内容が表示されます。 FullName フィールド。
このとき、 Mendix クライアントは、初期値と変更された値の両方を保存します。 FullName フィールド。コンソールからオブジェクトをリクエストすることで確認できます。 mx.data.get 返された値を比較すると MxObject.get (NAIST) と MxObject.getOriginalValue メソッド:

このアーティストを保存するには、 Save ボタンをクリックし、それがトリガーするリクエストを調べます (わかりやすくするために一部のフィールドは省略されています)。
{
"action": "commit",
"params": {
"guids": [
"5629499534213124"
]
},
"changes": {
"5629499534213124": {
"FullName": {
"value": "Pablo Picasso"
}
}
},
"objects": [{
"objectType": "MyFirstModule.Artist",
"guid": "5629499534213124",
"hash": "31doiDAq6u7/rMnqwWno01jhLkhpeQ+vKU/rI+IQor8=",
"attributes": {
"FullName": {
"value": null
}
}
}]
}
今回は commit アクションリクエストはランタイムに対して行われ、 guid データベースにコミットするオブジェクトの params フィールド。また、 changes フィールドには Pablo Picasso 私たちが行った変更と objects 含まれています Mendix 先ほど作成したオブジェクト。
応答は次のとおりです。
{
"commits": [
"5629499534213124"
],
"changes": {},
"resets": {
"5629499534213124": [
"FullName"
]
},
"deletes": [],
"newpersistable": [],
"objects": [{
"objectType": "MyFirstModule.Artist",
"guid": "5629499534213124",
"hash": "31doiDAq6u7/rMnqwWno01jhLkhpeQ+vKU/rI+IQor8=",
"attributes": {
"FullName": {
"value": "Pablo Picasso"
}
}
}]
}
ありません actionResult 今回はフィールドですが、州には多くの変更があります。
- その
commitsフィールドには、guidArtistコミットしたばかりなので、クライアントの状態はそれがもう新しいオブジェクトではないことを認識しています。 - その
resetsフィールドにはguidArtistそして、FullNameフィールドの変更は削除されます (コミットされたため)。クライアントは、この変更を状態から削除できるようになりました。
その objects フィールドはコミットされたオブジェクトの最新バージョンを表すようになり、 FullName フィールド値が設定されている Pablo Picasso.
ランタイムがコミットされたオブジェクトを再度返すのはなぜですか?
クライアントは既にその状態のオブジェクトを持っており、それを再利用できるのに、なぜランタイムはそれを再度返すのでしょうか? 理由は 2 つあります。
- オブジェクトには、オブジェクトをさらに変更するイベント ハンドラがある可能性があります。
- オブジェクトには計算属性があり、コミット時にその値が変更されている可能性があります。
そのため、クライアントはオブジェクトの最新の値を必要とし、それがランタイムから返されます。
アプリケーションは次のようになります。

今の状態を調べてみると、 Pablo Picasso リスト ビューで使用されているため、まだ状態にあります。ただし、小さな違いがあります。それは、もはや新規としてマークされていないことです。
{
"5629499534213124": {
"subscribedWidgets": [
"MyFirstModule.Artist_Overview.listView1",
"MyFirstModule.Artist_Overview.textBox1"
]
}
}
その Mendix クライアントはクライアント状態をキャッシュ層としても使用します。オブジェクトがその状態にあり、ウィジェットに必要な場合、ランタイムから再度取得されることはありません。 アーティストを編集 「パブロ・ピカソ」のボタンをクリックし、 ネットワーク タブを開きます。新しい xas 取得要求が行われる Pablo Picasso ランタイムから。すでに状態になっているので、要求する必要はありません。
クリックしてみましょう キャンセル 編集ページで、クリックしてアプリケーションのホームページに移動します ホーム メニュー項目を選択し、状態を確認します。
{
"MyFirstModule.Artist": {
"5629499534213124": "Going to be garbage collected †"
}
}
約15秒後に状態を確認してください。空になっていることがわかります。
しかし、それはなぜですか?
この質問への答えは、新しい概念、つまり状態からのガベージコレクションにあります。このメカニズムは、状態から不要なオブジェクトを検出して削除するため、作成または使用するオブジェクトの数に関係なく、アプリケーションは最高のパフォーマンスを発揮します。私たちのアプリケーションでは、 Pablo Picasso ホーム ページを開いてからは、ウィジェットに表示されていないため、オブジェクトは不要になりました。そのため、オブジェクトは状態から削除されます。ただし、状態からのガベージ コレクションは複雑なトピックであるため、このブログ シリーズのパート 2 で取り上げます。
この投稿を楽しんで読んでいただき、お役に立てていただければ幸いです。パート 2 でお会いしましょう。
