1

私は C# 開発者ですが、cqrs の構造と基本を学びたいので、言語が Java であるかどうかに関係なく、そこにある cqrs に関するほぼすべてのチュートリアルを読みました。

しかし、チュートリアルには違いがあり、今では混乱しており、どのテクニックを使用する必要があるのか​​ わからないため、チュートリアルをたくさん読んだことが問題だと思います.

私の頭の中では 2 つの主要な質問が飛び交っています。

  1. コマンド側では、たとえば ORM を呼び出すロジックをどこに配置すればよいですか? いくつかのチュートリアルでは、コマンド ハンドラーでそれを行います (私にとってはより多くのロジックです)。一部のチュートリアルでは、コマンド ハンドラーによって起動されるイベント ハンドラーでそれを行います。その場合、検証ロジックのみを行います。

  2. イベント ストアと考えを元に戻すには、どのデータをデータベースに保存する必要がありますか。一部のチュートリアルでは集計を保存し、一部のチュートリアルではイベント モデルを保存します。

誰かがどのパターンを使用するのか、そしてその理由を説明してくれることを願っています。おそらく両方とも異なるシナリオで、私にはわかりません。

実際の例は素晴らしいでしょう。(疑似コードのみ)
おそらくユーザー登録、RegisterTheUser コマンド:

やるべきこと:

  • ユーザー名がすでに使用されているかどうかを確認する
  • ユーザーをデータベースに追加
  • 確認メールを送信する (コマンドまたは UserIsRegistered イベントで?)
  • イベントConfirmationMailSendedまたはUserIsRegisteredイベントのみを発生させますか?

敬具

編集:これが私の現在の実装です(シンプル)

public class RegisterTheUser : ICommand
{
    public String Login { get; set; }

    public String Password { get; set; }
}


public class RegisterTheUserHandler : IHandleCommand<RegisterTheUser, AccountAggregate>
{
    public void Handle(AccountAggregate agg, RegisterTheUser command)
    {
        if (agg.IsLoginAlreadyInUse(command.Login))
            throw new LoginIsAlreadyInUse();

        agg.AddUserAccount(command);

        CommandBus.Execute<SendMail>(x => { });

                    EventBus.Raise<UserIsRegistred>(x => { x.Id = agg.UserAccount.Id; });
    }
}


public class UserIsRegistred : IEvent
{
    public Guid Id { get; set; }
}


public class AccountAggregate : AggregateBase
{
    public AccountAggregate(IUnitOfWork uow)
    {
        UnitOfWork = uow;
    }


    private IUnitOfWork UnitOfWork { get; set; }


    public UserAccount UserAccount { get; set; }


    public void AddUserAccount(RegisterTheUser command)
    {
        UserAccount = new UserAccount
        {
            Id = Guid.NewGuid(),
            IsAdmin = false,
            Login = command.Login,
            Password = Crypto.Sha512Encrypt(command.Password)
        };

        UnitOfWork.UserAccountRepository.Add(UserAccount);

        UnitOfWork.Commit();
    }


    public Boolean IsLoginAlreadyInUse(String login)
    {
        var result = UnitOfWork.UserAccountRepository.SingleOrDefault(x => x.Login == login);

        return (result != null);
    }
}
4

1 に答える 1

1

質問が多いのですが、回答させていただきます。

コマンド側では、たとえば ORM を呼び出すロジックをどこに配置すればよいですか?

このロジックをコマンド ハンドラーまたはイベント ハンドラーのいずれかに配置するかどうかは、構築しているシステムの種類に大きく依存します。非常に単純なシステムを使用している場合は、おそらく、ドメインによって発生したイベントを受け取るイベント ハンドラーに永続化ロジックを含めることができます。ここでの考え方は、コマンド ハンドラーによって処理されるコマンドには必要な情報が既に含まれており、コマンド ハンドラーは最終的にルーター以上のものではないということです。サガ、長時間実行されるトランザクション、または検証の追加レイヤーの処理など、コマンド ハンドラーでより複雑な処理が必要な場合、コマンド ハンドラーはここで永続化レイヤーを使用してデータを引き出し (おそらくデータを書き込み)、ルーティングします。コマンドを適切なドメインに送信するか、さらにコマンドを発行するか、イベントを発生させます。

私は、最初は複雑さよりもシンプルさを好む傾向があり、最初はイベント ハンドラーにそのロジックを含めることを検討するでしょう。システムがより複雑な場合は、コマンド ハンドラーに移動します。

イベントストアと思考を元に戻すために、どのデータをデータベースに保存する必要がありますか。一部のチュートリアルでは集計を保存し、一部のチュートリアルではイベントモデルを保存します

ここで何を求めているのか正確にはわかりませんが、イベント ストアに何を保存する必要があるのか​​ を尋ねている場合、簡単な解決策は集約 ID、集約タイプ、データを含むイベント (シリアル化) だと思います。そしてイベントの種類。私の頭の上から、それはおそらくあなたが必要とするものの骨組みです: 使用している集約 ID に基づいて、その集約のすべてのイベントを (発生した順序で) 取得し、それらを再生して集約を再構築します。 . やむを得ない理由がない限り、集計を保存する必要はないと思います (これは常に可能です)。

実際の例とあなたが提示した手順に対するあなたの要求については、それ自体がおそらく疑問ですが、それについての私の考えは次のとおりです。

  • ユーザー名が既に使用されているかどうかを確認するアプリケーションによっては、コマンドを発行する前に、コントローラー (またはコマンドを発行しているレイヤー) の読み取り側からこれを実行する必要がある場合があります。その時点で検証しますが、永続化する前に再度検証することをお勧めします。データベースの一意のインデックスに違反しているため、おそらく例外をキャッチするイベントハンドラーでこれを行うことができます。

  • DB にユーザーを追加 繰り返しますが、ドメインが UserIsRegistered イベントを発生させているため、シンプルに保ち、イベント ハンドラーで処理することを考えています。

  • 確認メールを送信する ドメインで UserIsRegistered イベントが発生し、2 番目のイベント ハンドラー (EmailHandler) もそのイベントをサブスクライブしてメールを送信する可能性があります。

  • ConfirmationMailSent イベントは、イベント ハンドラーによって発生し、イベント キューに追加され、それに応じて処理されます。私はあなたがここで何をしたいのかわからないと思います。

しかし、うまくいけば、これは少し役立ちます。

于 2013-06-27T13:57:14.310 に答える