3

バックグラウンド

私が理解しているように、Unit of Work (UoW) パターンは基本的にトランザクション セマンティクスを提供します。つまり、リポジトリによって永続化された集約のドメインが与えられた場合、UoW クラスを使用すると、ドメインのコンシューマーはリポジトリ メソッドの呼び出しをアトミック操作に登録できます。私たちが持っているとしましょう:

interface IAggregate<TKey> {
    TKey Id { get; }
}

interface IRepository<TEntity, in TKey> where TEntity : IAggregate<TKey> {
    TEntity Get(TKey id);
    void Save(TEntity entity);
    void Remove(TEntity entity);
}

interface IUnitOfWork {
    void RegisterSave<TEntity>(TEntity entity);
    void RegisterRemove<TEntity>(TEntity entity);
    void RegisterUnitOfWork(IUnitOfWork uow);
    void Commit();
    void Rollback();
}

の実装はIRepositoryリレーショナル データベースを使用し、 の実装はIUnitOfWork.Commit単にデータベースとのトランザクションをセットアップし、登録されたすべての操作に対して適切なインスタンスでSaveorを呼び出します。上で概説したことは、Aggregate Root、Repository、および UoW パターン (NHibernate/EF とそのすべての肥大化した栄光にもかかわらず) の標準的で直接的な解釈であると言えます。RemoveIRepository

これまで、私は集約ルート境界の概念を、ある集約から別の集約への参照を、ソース集約のターゲット集約の Id プロパティによってオブジェクト化する必要があるという意味として解釈してきました。例えば:

class User : IAggregate<int> {
  int Id { get; private set; }
}

class Blog : IAggregate<int> {
  int Id { get; private set; }
  int AuthorUserId { get; set; }
}

質問

上記の関心の分離と集約境界の解釈を考えると、トランザクションで集約を作成し、リポジトリで生成された Id を別の集約に保存する必要がある消費者にトランザクション サポートをどのように提供しますか? たとえば、 と を に設定しUserBlogトランザクション的に作成するにはどうすればよいですか?Blog.UserIdUser.Id

私はいくつかの回答を思いつきました (コミュニティ wiki とマークされています) が、とにかくここに私の質問を投稿して、フィードバックとより多くの回答を求めています。

4

3 に答える 3

1

上記の関心の分離と集約境界の解釈を考えると、トランザクションで集約を作成し、リポジトリで生成されたIDを別の集約に保存する必要があるコンシューマーにトランザクションサポートをどのように提供しますか?たとえば、Blog.UserIdをUser.Idに設定して、トランザクションでユーザーとブログを作成するにはどうすればよいですか?

物事は-骨材はトランザクションの境界も描く責任があります。つまり、ブログの作成が何らかの理由で失敗した場合に、ブログでユーザーを作成し、ユーザーの作成をロールバックする必要はありません。

そのような必要がある場合-あなたは骨材を間違ってモデリングしています。


役に立つかもしれないいくつかの簡単なコメントを投稿するだけです...

interface IAggregate<TKey> {
    TKey Id { get; }
}

インターフェイスは、実装クラスが保持するもの(この場合はキータイプに関する知識)ではなく、動作(ロール)を定義するために使用する必要があります。

適切な説明を見つけるのに十分な速さでグーグルできませんが、なぜそうなのか...後で試してみます。

interface IRepository<TEntity, in TKey> where TEntity : IAggregate<TKey> {
  TEntity Get(TKey id);
  void Save(TEntity entity);
  void Remove(TEntity entity);
}

一般的なリポジトリの使用は避けてください。

interface IUnitOfWork {
  void RegisterSave<TEntity>(TEntity entity);
  void RegisterRemove<TEntity>(TEntity entity);
  void RegisterUnitOfWork(IUnitOfWork uow);
  void Commit();
  void Rollback();
}

作業単位の使用を避けてください(これはあなたの問題を解決します)。

interface IAggregate<TSelf> where TSelf : IAggregate<TSelf>
{
    IKey<TSelf> Id { get; }
}

学び続けます。すぐに、インターフェイスとジェネリックの悪用をやめます。:)

于 2011-01-23T03:48:47.717 に答える
0

ID 型は参照型としてスマートにする必要がありますか? そうすれば、リポジトリが ID を更新するときに、別の集計による参照を介してアクセスできます。例えば:

interface IKey<TAggregate> : IEquatable<IKey<TAggregate>>
{
    /* should provide a ctor that accepts a string */

    TAggregate GetAggregateType();
    string ToString();
    bool IsAssigned { get; }
}

interface IAggregate<TSelf> where TSelf : IAggregate<TSelf>
{
    IKey<TSelf> Id { get; }
}

interface IRepository<TAggregate> where TAggregate : IAggregate<TAggregate>
{
    TAggregate Get(IKey<TAggregate> id);
    void Save(TAggregate entity);
    void Remove(TAggregate entity);
}

class User : IAggregate<User>
{
    public IKey<User> Id { get; private set; }
}

class Blog : IAggregate<Blog>
{
    public IKey<Blog> Id { get; private set; }
    public IKey<User> Author { get; private set; }
}

の実装はIKey<TAggregate>、 の実装と同じパッケージで提供されますIRepository<TAggregate>

于 2011-01-20T04:18:53.940 に答える
0

次のパターン制約のいずれかを緩める必要があるようです。

  • リポジトリは、集約 ID の生成を担当します。代わりに、自然キーを使用する必要があります。
  • UoW は任意のActionデリゲートを登録できません。代わりに、UoW が任意の を登録できるようにしますActions
  • 集計間の関係は、ID プロパティとしてオブジェクト化されます。代わりに、次のような集計型のプロパティを使用してください。

 

partial class Blog : IAggregate<int> { 
  User Author { get; set; } 
}

では、パターンを間違って解釈したのでしょうか? それとも、この点で実際に制限されていますか?

于 2011-01-20T04:20:02.223 に答える