2012-09-09 2 views
12

を更新するために必要な詳細情報が含まれていません。CQRSイベントは、私が得ることはありませんCQRSについての一つのことがあります読んモデル

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

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

ここで、イベントハンドラはこのイベントと両方のIDを受け取ります。ここには、そのグループの名前を持つすべてのユーザーをリストするビューがあります。そのビューの読み取りモデルを更新するには、ユーザーID(グループID)とグループ名(グループIDは必要ありません)私たちはそのIDだけを持っています)。

質問は次のとおりです。このシナリオをどのように処理すればよいですか?

現在、4つのオプションは、私の心に来て、彼らの特定の欠点を持つすべて:

  1. 読み取りモデルがドメインを要求します。 =>禁止されていても、ドメインは行動しか持たないため、(公開されていない)状態である。

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

  3. イベントに必要なデータを追加します。 =>これは、以前のすべてのイベントも更新する必要があることを意味し、どのデータが1日必要なのか予見できません。

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

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

答えて

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%を取得するなど)。 )processi中のng。

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

+0

さて、これまでのところ、私はそれを得ました;-) 私がまだ得られなかったものは:PurchaseOrderSubmittedイベント_today_にVATが含まれていないと仮定します。今、私が行っている将来のある時点に早送りします。 もちろん、VATを含む新しいイベント、基本的にV2.0を作成することはできますが、これは過去のすべてのオーダーを手伝ってくれませんか? どうすれば対処できますか? –

+1

モデルの構造とイベントの構造を互いに独立して変更することができます。モデルが新しい情報(VATなど)で拡張されると、古いイベントのハンドラーはそのまま、または新しいプロパティーをデフォルト値に設定します。新しい列をデータベーステーブルに追加するときと同じように、次のようにします。新しい列は、すべての文字エントリに対してnullまたはデフォルトのいずれかに設定する必要があります。イベントが再生されたり、読み込みモデルの水和に使用されるたびに、新しいフィールドは必要なデフォルト値に設定されます。 –

+0

さて、ありがとう、それは意味をなさない:-)! –

7

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

「イベント濃縮は」あなたは確かにあなたが言及されている情報を反映したイベント、例えば上の情報を置く場所である1)グループ名これは、ドメインのモデリングと不正行為の間のどこかで行われます。たとえば、そのグループ名が変更されていることが分かっている場合、変更の瞬間に名前を表示することは悪い考えではありません。見積もりや請求書に広告申込情報を作成したときに、請求書作成イベントで販売された商品の価格を放棄したいとします。これは、たとえ後で変更されたとしても、その価格を尊重しなければならないからです。

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

+0

ありがとうございました。 –

+1

私は#2を理解しているか分かりません。プロジェクションはストリームに問い合わせるか、新しいイベントを待つだけですか?このプロセスを検索するために重要な作業はありますか?私は "イベントの豊かさ"を学んだが、それは悪いslnのようだ。 – Raif

+0

プロジェクションは、通常、1つ以上のストリームがイベントを発生するときに「連続的に」読み込み、変更をリレーショナルデータベースなどの読み取りモデルに投影するコンポーネントです。 –

0

オプション2は問題ありません。「グループの名前の読取りモデルのテーブルの不一致はどうでしょうか」という質問は適用されません。データを削除する必要はありません。以前のイベント(グループの削除)がエミュレートされたときに無効にする必要があります。最後に、グループテーブルの行が効果的に存在し、問題なくグループ名を読むことができます。明白な唯一の問題はスピードの矛盾ですが、それは別の問題です。イベントはスピードに関係なく整然と処理されるべきです。

関連する問題