45

Fowler(ここ)によると、リポジトリは「ドメインとデータマッピングレイヤーの間を仲介し、メモリ内のドメインオブジェクトコレクションのように機能します」。したがって、たとえば、私のCourier Serviceアプリケーションでは、新しい実行が送信されると、アプリケーションサービスは新しいRun集約ルートオブジェクトを作成し、リクエストからの値を入力してからRunRepositoryに追加してから、作業ユニットを呼び出して保存します。データベースへの変更。ユーザーが現在の実行のリストを表示したい場合、同じリポジトリにクエリを実行し、情報を表す非正規化されたDTOを返します。

ただし、CQRSを見ると、クエリは同じリポジトリにヒットしません。代わりに、データストアに直接逆行し、常に非正規化される可能性があります。そして、私のコマンド側はNewRunCommandとHandlerに進化し、NewRunドメインオブジェクトを作成してデータを設定し、その情報をデータストアに永続化します。

したがって、最初の質問は、ドメインオブジェクトのメモリ内コレクション(必要に応じてキャッシュ)を維持していない場合、リポジトリはCQRSモデルのどこに適合するのかということです。

アプリケーションサービスに送信された情報に、ドメインオブジェクトを構築するためにサービスが解決する必要のある一連のID値しか含まれていない場合を考えてみます。たとえば、リクエストには、実行に割り当てられた宅配便のID番号が含まれています。サービスは、ID値に基づいて実際のCourierオブジェクトを検索し、AssignCourierメソッド(Courierを検証して他のビジネスロジックを実行する)を使用してオブジェクトをNewRunに割り当てる必要があります。

もう1つの質問は、クエリが分離され、リポジトリが存在しない可能性がある場合、アプリケーションサービスはCourierドメインオブジェクトを見つけるためにどのようにルックアップを実行するのでしょうか。

アップデート

デニスのコメントの後のいくつかの追加の読書と考えに基づいて、私は私の質問を言い換えます。

CQRSは、データアクセスおよびデータストレージメカニズムの単なるファサードであるリポジトリを推奨しているように思われます。それらはコレクションの「外観」を提供しますが(Fowlerが説明するように)、メモリ内のエンティティを管理していません(Dennisが指摘したように)。これは、リポジトリでのすべての操作がパススルーであることを意味しますね。

作業単位はこのアプローチにどのように適合しますか?通常、UoWはリポジトリに加えられた変更をコミットするために使用されます(右?)が、リポジトリがエンティティをメモリ内に維持していない場合、UoWにはどのような役割がありますか?

「書き込み」操作に関して、コマンドハンドラーは、同じリポジトリ、別のリポジトリ、またはリポジトリではなくUoWへの参照を持ちますか?

4

2 に答える 2

14

コマンド側で単純なキー値ストアを維持してアプリケーションの状態を表すCQRSシステムや、メッセージを単に相関させ(ある種のサガを使用)、代わりにクエリストアを使用してアプリケーションの状態を表すCQRSシステムについて読んだことがあります。いずれにせよ、これらのアプローチに関連する永続化テクノロジーがあることは間違いありませんが、これらの場合のリポジトリパターンは、その上に不必要な抽象化になります。

CQRSでの私の経験は、これまでイベントソーシングでのみでした。ここでは、過去のイベントを再生して、ビジネスロジックと不変条件をカプセル化して適用する集計を再構築しました。この場合、リポジトリパターンはおなじみの抽象化であり、これらの集計を取得するためのより簡単な方法を提供できます。

クエリ側に関しては、データストアにできるだけ近づけることをお勧めします。これは、UI(それが何であれ)とデータストアの間にリポジトリ、サービス、ファサードなどを避けることを意味します。

これらのアプローチの使用例を確認すると役立つ場合があります。たぶん、次のプロジェクトを見てください。

NESの場合、リポジトリは、作業単位との間で直接集計を追加および読み取るための使い慣れたインターフェイスを提供するだけです。

役立つかもしれないいくつかのより多くのリンク:

于 2012-04-18T00:50:58.203 に答える
1

これがどれほど正統であるかはわかりませんが、現在のプロジェクトでは、集約エンティティルートのリポジトリがあります。このリポジトリには、GetとApplyEventsの2つのメソッドしかありません。

すべてのイベントは、そのタイプに共通のインターフェイスを実装します。注文には、OrderEventsなどがあります。私は各イベントのビジネスロジックをポリモーフィックメソッドに個人的に入れて、新しいタイプのイベントを非常に簡単に追加できるようにします。

Getの場合、リポジトリはイベントストアに移動し、そのタイプのスコープ内のすべてのイベントを取得します(たとえば、単一のストアの場所の注文)。次に、イベントの再生を実行して、指定されたすべてのイベントのエンティティの現在の状態に到達します。スナップショットからも機能するため、ロードするたびにすべてのイベントを再作成する必要はありません。また、一般的なイベントリポジトリを使用して、イベントの保存方法を抽象化し、仕様に基づいてイベントを取得することもできます。

ApplyEventsはイベントのリストを受け取り、これらに基づいてエンティティの状態を変更し、それを返します。エンティティを変更するだけでなく、エンティティを再作成するオプションをリポジトリに提供していることに注意してください。これは機能的なタイプのプログラミングでうまく機能しますが、C#またはJavaではオブジェクトの同等性(obj1 == obj2)を回避するのが最善であることを意味します。とにかく、エンティティではなく、ValueObjectsだけが同等である必要があると私は主張します。

実際の動作は次のとおりです(C#)-注文があり、アイテムを追加したいと思います。currentOrder.Itemsは空のリストを返しています。それから私はします

Assert.IsFalse(newEvent.Items.Any())
IOrderEvent newEvent = eventFactory.CreateOrderItemEvent(myItemID);
currentOrder = orderRepository.ApplyEvents(currentOrder, newEvent);
Assert.IsTrue(newEvent.Items.Any())

currentOrder.Itemsに1つのエントリがあることがわかります。

ここでの欠点は、エンティティにビジネスロジックを含めるのではなく、すべての処理がイベントを介して行われることです。ただし、私の場合、ほとんどすべてのオブジェクトがシリアル化可能(基本的にPOCO)であり、複数のシステムで動作する必要がある場合、これは実際にはうまく機能します。

于 2014-06-13T17:57:54.053 に答える