8

ドメインイベントと合わせてドメイン駆動設計について勉強しています。私は、これらのイベントが提供する懸念事項の分離が本当に気に入っています。ドメイン オブジェクトの永続化とドメイン イベントの発生の順序で問題が発生しました。ドメイン オブジェクトでイベントを発生させたいと考えていますが、永続性を考慮しないようにしたいと考えています。

ShoppingCartServiceこのCheckoutメソッドを使用して、基本的な を作成しました。

public void Checkout(IEnumerable<ShoppingCartItem> cart, Customer customer)
{
    var order = new Order(cart, customer);

    _orderRepositorty.Add(order);
    _unitOfWork.Commit();
}

この例では、のコンストラクターは、特定のハンドラーによって処理できるイベントを発生させますOrderOrderCreatedただし、エンティティがまだ永続化されていない場合、または永続化が何らかの形で失敗した場合に、これらのイベントが発生することは望ましくありません。

この問題を解決するために、私はいくつかの解決策を考え出しました:

1. サービスでイベントを発生させます。

ドメイン オブジェクトでイベントを発生させる代わりに、サービスでイベントを発生させることができます。この場合、CheckoutメソッドはOrderCreatedイベントを発生させます。このアプローチの欠点の 1 つは、Orderドメイン オブジェクトを見ると、どのイベントがどのメソッドによって発生したかが明確でないことです。また、開発者は、注文が別の場所で作成されたときにイベントを発生させることを覚えておく必要があります。気分が悪い。


2. ドメイン イベントをキューに入れる

もう 1 つのオプションは、ドメイン イベントをキューに入れ、永続化が成功したときに発生させることです。usingこれは、たとえば次のステートメントで実現できます。

using (DomainEvents.QueueEvents<OrderCreated>())
{
    var order = new Order(cart, customer);

    _orderRepositorty.Add(order);
    _unitOfWork.Commit();
}

QueueEvents<T>メソッドはブール値を に設定しtrue、メソッドDomainEvents.Raise<T>はイベントを直接実行するのではなくキューに入れます。の破棄コールバックでQueueEvent<T>は、キューに入れられたイベントが実行され、永続化が既に行われていることが確認されます。これはややこしいようで、ドメイン オブジェクトでどのイベントが発生しているかをサービスが認識できるようにする必要がありました。私が提供した例では、発生するイベントの 1 つのタイプのみをサポートしていますが、これは回避できます。


3. ドメイン イベントに永続化する

ドメイン イベントを使用してオブジェクトを永続化できます。オブジェクトを永続化するイベント ハンドラーを最初に実行する必要があるという事実を除いて、これは問題ないように思えますが、ドメイン イベントは特定の実行順序に依存してはならないことをどこかで読みました。おそらくそれはそれほど重要ではなく、ドメイン イベントはハンドラーがどの順序で実行されるべきかをどうにかして知ることができます。例: ドメイン イベントハンドラーを定義するインターフェイスがあるとします。実装は次のようになります。

public class NotifyCustomer : IDomainEventHandler<OrderCreated>
{
   public void Handle(OrderCreated args)
   {
       // ...
   }
}

イベント ハンドラーを使用して永続化を処理したい場合は、同じインターフェイスから派生する別のハンドラーを作成します。

public class PersistOrder : IDomainEventHandler<OrderCreated>
    {
       public void Handle(OrderCreated args)
       {
           // ...
       }
    }
}

現在NotifyCustomer、動作はデータベースに保存されている順序に依存するため、PersistOrderイベント ハンドラーを最初に実行する必要があります。これらのハンドラーが、たとえば実行順序を示すプロパティを導入することは許容されますか? メソッドの実装からのスナップDomainEvents.Raise<OrderCreated>():

foreach (var handler in Container.ResolveAll<IDomainEventHandler<OrderCreated>>().OrderBy(h => h.Order))
{
    handler.Handle(args);
}


私の質問は、他に選択肢はありますか?何か不足していますか?そして、私が提案した解決策についてどう思いますか?

4

2 に答える 2

7

(トランザクション) イベント ハンドラーが (潜在的に分散された) トランザクションに参加するか、トランザクションがコミットされた後にイベントを発行/処理します。あなたの "QueueEvents" ソリューションは基本的なアイデアを正しく理解していますが、リポジトリやイベント ストア経由で公開するなど、より洗練されたソリューションがあります。例として、SimpleCQRSを見てください。

次の質問と回答も役立つ場合があります。

CQRS: イベントの保存と公開 - これを安全に行うにはどうすればよいですか?

ロールバックによるイベント アグリゲーターのエラー処理


ポイント3の更新:

...しかし、ドメインイベントは特定の実行順序に依存してはならないことをどこかで読みました。

永続化の方法に関係なく、イベントの順序は (集約内で) 絶対に重要です。

現在、NotifyCustomer の動作はデータベースに保存されている順序に依存するため、PersistOrder イベント ハンドラーを最初に実行する必要があります。これらのハンドラーが、たとえば実行順序を示すプロパティを導入することは許容されますか?

イベントの永続化処理は別の問題です。イベント ハンドラーを使用して永続化しないでください。最初に永続化してから処理します。

于 2014-03-06T10:29:23.490 に答える