web-dev-qa-db-ja.com

CQRSで新しい集約ルートを作成する方法は?

Cqrsアーキテクチャで新しい集約ルートを作成するにはどうすればよいですか?この例では、最初の1つのAR1への参照を保持する新しい集約ルートAR2を作成します。

開始点としてAR1メソッドを使用してAR2を作成しています。これまでのところ、いくつかのオプションが表示されます。

  1. AR1の内部メソッド_createAr2RootOpt1_ new AR2()を呼び出して、リポジトリにアクセスできるドメインサービスを使用して、このオブジェクトをimediatellyにdbに保存できます。
  2. たとえば、最初の集約ルートでイベントを発行できます。 _SholdCreateAR2Event_そして、これに反応してコマンド_CreateAR2Command_を発行するステートレスサガがあり、これが処理されて実際にAR2を作成し、_AR2CreatedEvent_を発行します。イベントソースを使用する場合、_SholdCreateAR2Event_は最初の集約ルートの状態に影響しないため、イベントストアに保持されません。 (または、これをイベントストアに保存する必要がありますか?)

    _class AR1{
        Integer id;
        DomainService ds;
    
        //OPTION 1
        void createAr2RootOpt1(){
            AR2 ar2 = new AR2();
            ds.saveToRepo(ar2);
        }
    
        //OPTION 2
        void createAr2RootOpt2(){
            publishEvent(new SholdCreateAR2Event());    //we don't need this event. Shoud it still be preserved in event store?
        }
    }
    
    class AR2{
        Integer id;
        Integer ar1Id;
    
        void handle(CreateAR2Command command){
            //init this AR with values and save
            publishEvent(AR2CreatedEvent());    //used for projections afterwards and saved inside AR2 event store
        }
    }
    
    class Saga{
        void handle(SholdCreateAR2Event ev){
            emitCommand(new CreateAR2Command());
        }
    }
    _

これを行うためのより適切な方法はどれですか?

10
Bojan Vukasovic

Cqrsアーキテクチャで新しい集約ルートを作成するにはどうすればよいですか?

作成パターンはweirdです。

Udi Dahanには、一般的な問題についていくつかの便利な点があります: Do n't Create Aggregate Roots 。基本的なポイントは、その集合体がどこからともなく出てくるわけではなく、それらがどのように表示されるかを説明するドメイン言語があり、ドメインモデルに取り込む必要があるということです。

ツイストする傾向があるのは、コマンドを処理しているドメインモデル内のエンティティがないエンティティがトランザクションによって変更されることです。それは間違いではありません。 (エンティティに自分自身を変更するように依頼する場合と比較して)奇妙です。

2番目のアプローチも問題ありません。 「実際にデータベースに保存せずに発生させるイベント」は、「ドメインイベント」と呼ばれることもあります

基本的な考え方は、同じトランザクション内で、コマンドハンドラーがイベントを発生させ、それがバスに沿ってイベントハンドラーに移動し、2番目の集約がそれ自体を作成できるようにすることです。おそらく、コードのまとまりが多少良くなります。

注:イベントソースシステムでは、通常、この方法でイベントを使用しません。

イベントソースを使用する場合、ShouldCreateAR2Eventは最初の集約ルートの状態に影響しないため、イベントストアに保存されません。

注:通常、イベント名は過去形です-ShouldCrateAR2のスペルが間違っています。

はい、イベントを同期バスにスローしてリモートコードを実行しているだけの場合は、そのイベントを記録簿に保存しないでください。このスケールでの実装の詳細にすぎません。

それとも、これをイベントストアに保存する必要がありますか?

同じトランザクションで2つの異なるイベントストリームを変更しないでください。この作成がAR1への変更も表す場合、通常の答えは、このトランザクションでAR1を変更することです。asynchronousのサブスクライバーは、 AR2を作成するコマンドを起動する責任があります。

べき等のコマンド処理は、ここで非常に役立ちます。

2
VoiceOfUnreason

私はそのオプションはないと思います。 2は解決策ですが、小さな重要な変更が加えられています。AR1は、AR2を作成することを目的としたイベントを発行するのではなく、AR1WasCreatedイベントを発行する必要があります。このイベントは、AR1の誕生を示す重要なイベントであるため、イベントストアに永続化する必要があります。次に、SagaAR1WasCreatedイベントをリストし、AR2を作成するコマンドを生成します:CreateAR2Command

オプションno.1は非常に間違っています。この種のドメインサービスをAggregateに挿入しないでください。 Aggregatesは純粋である必要があり、イベントの生成以外の副作用はありません。

追伸オブジェクトのインスタンスの作成(プログラミング言語の意味で)とAggregateの作成(必要に応じて誕生)には違いがあるため、私はAggregateのコンストラクターからイベントを発行しません。 handleメソッドからのみイベントを発行します(commandを処理する場合)。

2