18

CQRSについて、私が得られないことが1つあります。発生したイベントに、読み取りモデルの更新に必要な詳細が含まれていない場合に、読み取りモデルを更新する方法です。

残念ながら、これは非常に一般的なシナリオです。

例:ユーザーをグループに追加するので、addUserToGroup(userId、groupId)コマンドを送信します。これは、コマンドハンドラーによって受信、処理され、userAddedToGroupイベントが作成、保存、および公開されます。

これで、イベントハンドラーはこのイベントと両方のIDを受け取ります。これで、すべてのユーザーとそのグループの名前を一覧表示するビューが表示されます。そのビューの読み取りモデルを更新するには、ユーザーID(私たちが持っている)とグループ名(私たちが持っていない)が必要です。持っている、私たちはそのIDしか持っていない)。

したがって、問題は次のとおりです。このシナリオをどのように処理しますか?

現在、4つのオプションが頭に浮かびますが、すべて特定の欠点があります。

  1. 読み取りモデルはドメインに問い合わせます。=>ドメインには動作のみがあり、(パブリック)状態がないため、禁止されており、不可能ですらあります。

  2. 読み取りモデルは、読み取りモデルの別のテーブルからグループ名を読み取ります。=>動作しますが、一致するテーブルがない場合はどうなりますか?

  3. 必要なデータをイベントに追加します。=>これは、以前のすべてのイベントも更新する必要があり、いつか必要になる可能性のあるデータを予測できないため、機能しません。

  4. 「通常の」イベントハンドラーを介してイベントを処理しないでください。ただし、イベントストアを処理し、必要なデータを作成し、読み取りモデルを書き込むバックグラウンドでETLプロセスを開始します。=>動作しますが、このような単純なシナリオでは、これは少しオーバーヘッドが大きすぎるように見えます。

したがって、問題は次のとおりです。このシナリオを正しく処理するにはどうすればよいですか。

4

3 に答える 3

7

2つの一般的な解決策があります。

1)「イベントエンリッチメント」とは、グループ名など、言及している情報を反映したイベントに関する情報を実際に配置する場所です。これを行うことは、ドメインを適切にモデル化することと不正行為の間のどこかにあります。たとえば、グループ名が変更されることを知っている場合、変更の瞬間に名前を発行することは悪い考えではありません。見積もりまたは請求書にラインアイテムを作成するときに、請求書作成イベントで販売された商品の価格を発行するとします。これは、後で変更された場合でも、その価格を尊重する必要があるためです。

2)一度に複数のストリームを投影します。さまざまなストリームからの情報を監視し、それらを結合するプロジェクターを作成します。ユーザーとグループのイベント、およびグループイベントに追加されたユーザーを監視できます。システム内のイベントの順序によっては、グループの名前を知る前にユーザーがグループに属していることを知っている場合がありますが、始める前にイベントストアの一般的なプロパティを知っておく必要があります。

于 2012-09-09T16:24:10.247 に答える
5

イベントは、最初にプロセスを開始したコマンドの1対1のマッピングを必ずしも表すわけではありません。たとえば、コマンドがある場合:

SubmitPurchaseOrder
    Shopping Cart Id
    Shipping Address
    Billing Address

結果のイベントは次のようになります。

PurchaseOrderSubmitted
    Items (Id, Name, Amount, Price)
    Shipping Address
    Shipping Provider
    Our Shipping Cost
    Shipping Cost billed to Customer
    Billing Address
    VAT %
    VAT Amount
    First Time Customer
    ...

通常、情報はドメインモデルで利用できます(コマンドによって提供されるか、関連する集合体の既知の内部状態として、または処理の一部として計算されることによって)。

さらに、処理中に読み取りモデルまたは別のBC(たとえば、状態に応じて実際のVAT%を取得するため)を照会することにより、イベントを強化できます。

あなたは、イベントが時間とともに変化する可能性がある(そしておそらく変化する)と正しく想定しています。バージョニングを使用する場合、これは基本的にまったく問題ではありません。新しいイベント(たとえばSubmitPurchaseOrderV2)を追加し、それを消費することになっているすべてのクラスに適切なイベントハンドラーを追加します。古いイベントを変更する必要はありません。インターフェースを変更せずに拡張するため、引き続き使用できます。これは基本的に、実際のオープン/クローズド原則の非常に良い例に帰着します。

于 2012-09-09T21:33:13.037 に答える
0

オプション2は問題ありませんが、「グループの名前読み取りモデルテーブルの不一致についてはどうでしょうか」という質問は当てはまりません。データは削除しないでください。前のイベント(グループの削除など)が送信されたときに無効にする必要があります。最後に、グループテーブルの行が効果的に表示され、グループ名を問題なく読み取ることができます。唯一の明らかな問題は速度の不一致である可能性がありますが、それは別の問題です。イベントは、処理速度に関係なく、順番に処理する必要があります。

于 2013-04-18T14:27:11.543 に答える