この機能は、イベント・ドリブンでデータを扱うという新しいパラダイムで継続されています。4D 21は、データベース操作(保存やドロップ)に関連する一連のイベントを提供します。
ORDAイベントはトリガーに取って代わることができ、より多くの利点を提供します:よりコントロールしやすく、ビジネスロジック(請求書の印刷や外部データの保存などの時間のかかるジョブを含む)をORDAデータクラス関数で直接コーディングすることができます。新規、変更、保存、削除(CRUD)のようなデータレベルのイベントに応答します。
ORDAイベントは正確な粒度と洗練されたエラーハンドリングを提供し、強力な データ整合性とより良いコード編成をもたらします。
保存やドロップアクションの各ステップで適切なビジネスロジックを実装する方法をご覧ください。
ORDAイベント – 何度もワルツを踊る
前回のブログポストでは、長いシリーズの最初のイベントであるタッチイベントを紹介しました。
新しいデータベース操作イベントは 、トリガでは不可能な Thisキーワードで扱われるエンティティを通してORDAレイヤで使用されるように設計されています。
トリガーと比較して、これらのイベントは、特定のデータベース操作ステップを検出する ためのより細かい粒度と、必要に応じてアクションを停止することができる洗練されたエラー処理を提供します。
トリガーとは異なり、イベントはセーブ/ドロップアクションの前にアクションを実行できるだけではありません。また、セーブ/ドロップ操作中や操作後にアクションを実行することもできます。
エラーハンドリングは強力で、異なる深刻度や詳細な追加情報を持つカスタマイズされたエラーをエンドユーザーに返すことができます。
以前は、このためにいくつかの関数を実装することができましたが、必要なときに手動で呼び出す必要がありました。
現在、この機能は完全なイベントドリブンロジックを提供し、 適切なタイミングで自動的にトリガーされます。一度実装すれば、あとは4Dエンジンが実行時に処理してくれます:
- 一貫性のないデータは、永続化レイヤーを介さずに事前に拒否することができます。
- 外部システムとのインタラクションは、4Dデータが永続化されたときに発生します。
- セーブ/ドロップが失敗したときに、アクションをトリガーできる。
また、トリガーとは逆に、ORDAでは データクラスの 保存/削除時にテーブル全体をロックすることはありません。異なるエンティティ (つまりレコード)を含む限り、複数のイベントを並行して実行することができます 。
一意のシーケンス番号などを処理するためにテーブル全体の完全なロックに依存する場合は、シングルトンなどを使用して自分で処理する必要があります。
データベース操作の明確なフェーズ
セーブアクションやドロップアクションが実行されるとき、これらのイベントによって、アクションの3つの異なるフェーズでビジネスロジックを実装することができます:
- 保存または削除アクションの検証:このアクションに関するデータの整合性をチェックするのに便利です:
- ドロップされようとしているエンティティのステータスは “TO DELETE “に設定されているか?
- 予約エンティティの出発日<到着日ですか?
このイベントのおかげで、あなたは保存/ドロップアクションを停止し、エンドユーザーにエラーを返すことができます。これにより、セーブ/ドロップアクション自体に入る前にデータの一貫性と準備ができていることを保証します。
- セーブ/ドロップ中:データベース操作を外部システムと同期させる必要がある場合などに使用します:
- 例えば、エンティティの保存、ディスクへのデータの書き込み、Googleドライブへのドキュメントの作成などです。
このイベントでは、アクションの停止に失敗した場合にエラーを返すことができます。これらのエラーは、後述のアフターイベントで処理できます。
- 保存またはドロップアクションの後:ここでは、セーブ/ドロップアクション中に発生した潜在的なエラーに関する対策を講じることができます :
- ドロップアクション中にエラーが発生したため、商品を “To be checked “にする。
これらのイベントのおかげで、セーブ/ドロップアクションの各ステップは専用のビジネスロジックを持つことができます。
これらのイベントは、ORDAまたはRESTサーバーを使用してデータベース操作がトリガーされるとすぐにトリガーされます。
例を見てみましょう。
イベントを実装する場所
ORDA イベントはエンティティクラスでeventキーワードを使用して実装する必要があります。
検証イベント
これらのイベントは、セーブまたはドロップアクションの前にトリガされ、エラーを返すことでアクションを停止させることができます。 この場合、以下に説明する他のイベント(after イベントを除く)はトリガされません。
これらは実装可能です:
- 属性レベル:特定の属性の一貫性をチェックする。
- エンティティ・レベル:エンティティの内容をグローバルにチェックしたり、属性を比較したりする。
例
この例では、ProductsEntity クラスで、margin 属性に対して validateSaveイベントが実装されています。ユーザーは、マージンが 50% 未満の製品を保存できません。この場合、保存アクションを停止し、エンドユーザーにフィードバックを与えるためにエラーが返されます。
// ProductsEntity class
//
// validateSave event at attribute level
Function event validateSave margin($event : Object) : Object
var $result : Object
//The user can't create a product whose margin is < 50%
If (This.margin<50)
$result:={errCode: 1; message: "The validation of this product failed"; \
extraDescription: {info: "The margin of this product ("+String(This.margin)+") is lower than 50%"}; seriousError: False}
End if
return $result
同じロジックがvalidateDropイベントにも適用されます。例えば、ステータスが “To delete “でない商品をユーザーがドロップできないようにすることができます。
保存/削除イベント
これらのイベントは、保存またはドロップのアクション中に正確に トリガーされ、何か問題が発生した場合にエラーを返すことができます。以下のような実装が可能です:
- 属性レベル: 特定の属性値の変更を監視する。
- エンティティレベル:エンティティの内容をグローバルにチェックしたり、属性を比較したりする。
例
この例では、ProductsEntity クラスで、userManualPath 属性に対して 保存イベントが実装されています。製品が保存されると、ユーザ・マニュアル・ドキュメントがディスク上に作成され、そのパスが userManualPath 属性に格納されます。これら 2 つのアクションは一貫していなければなりません。
ディスク上にユーザーマニュアルドキュメントを作成する際にエラーが発生した場合、フィードバックとしてエラーが返され、次のイベント(afterSave)で処理されます。
ファイルの内容は、時間がかかるため、保存イベントの外で以前に生成されることに注意してください。
// ProductsEntity class
// saving event at attribute level
Function event saving userManualPath($event : Object) : Object
var $result : Object
var $userManualFile : 4D.File
var $fileCreated : Boolean
If (This.userManualPath#"")
$userManualFile:=File(This.userManualPath)
// The user manual document file is created on the disk
// This may fail if no more space is available
Try
// The content of the file has been generated and stored in a map in Storage.docMap previously
$docInfo:=Storage.docMap.query("name = :1"; This.name).first()
$userManualFile.setContent($docInfo.content)
Catch
// E.g.: No more space on disk
$result:={errCode: 1; message: "Error during the save action for this product"; extraDescription: {info: "There is no available space on disk to store the user manual"}}
End try
End if
return $result
同じロジックがドロップイベントにも適用されます。例えば、製品をドロップしながらユーザーマニュアルのドキュメントをドロップすることができます。
アフターイベント
これらのイベントはSaveまたはDropアクションの後にトリガーされます。アクションは終了しているので、エラーを返すことはできません。主な目的は、以前のイベント中にエラーが発生した場合にビジネスロジックをトリガーすることです。
エラーが発生しなかった場合は、成功後のロジックを処理することもできます。
これらのイベントはエンティティ・レベルでのみ実装されます。
例
この例では、ProductsEntity クラスにafterSaveイベントが実装されています。もし userManualPath 属性が以前に正しく保存されていない場合、その値はリセットされ、ディスク上のユーザー・マニュアル・ドキュメントの欠落に一致するようになります。
// ProductsEntity class
Function event afterSave($event : Object)
If (($event.status.success=False) && ($event.status.errors=Null)) // $event.status.errors is filled if the error comes from the validateSave event
// The userManualPath attribute has not been properly saved
// Its value is reset
If ($event.savedAttributes.indexOf("userManualPath")=-1)
This.userManualPath:=""
This.status:="KO"
End if
End if
同じロジックがafterDropイベントにも適用されます。たとえば、製品のドロップに失敗した場合、そのインシデントをログに記録できます。
注意 イベントでは、長い操作はできるだけ避けなければなりません。可能であれば、そのような操作は別の場所で実装する必要があります。
強力なデータ整合性に依存するために、イベントの実装を待ってはいけません。
ORDAイベントの実装の詳細については、HDIをダウンロードし、以下のビデオをご覧ください。
ENビデオリンクを追加
