37

この種の質問が何度も出されているにもかかわらず、リポジトリと作業単位のパターンの関係を理解するのに苦労しています。基本的に、どの部分がデータの変更を保存/コミットするのか、まだわかりません - リポジトリまたは作業単位ですか?

私が見たすべての例は、これらをデータベース/OR マッパーと組み合わせて使用​​することに関連しているため、より興味深い例を作成しましょう。データ ファイルでファイル システムにデータを永続化します。パターンによれば、データがどこに行くかは関係ないので、これを行うことができるはずです。

したがって、基本エンティティの場合:

public class Account
{
    public int Id { get; set; }
    public string Name { get; set; }
}

次のインターフェイスが使用されると思います。

public interface IAccountRepository
{
     Account Get(int id);
     void Add(Account account);
     void Update(Account account);
     void Remove(Account account);
}

public interface IUnitOfWork
{
    void Save();
}

そして、使い方としては以下のようになると思います。

IUnitOfWork unitOfWork = // Create concrete implementation here
IAccountRepository repository = // Create concrete implementation here

// Add a new account
Account account = new Account() { Name = "Test" };
repository.Add(account);

// Commit changes
unitOfWork.Save();

すべてのデータがファイルに永続化されることを念頭に置いて、このデータを実際に追加/更新/削除するロジックはどこに行くのでしょうか?

  1. Add()Update()およびRemove()メソッドを介してリポジトリに移動しますか? ファイルを読み書きするすべてのコードを 1 か所に配置するのは理にかなっているように思えますが、IUnitOfWorkインターフェイスのポイントは何でしょうか?
  2. IUnitOfWorkこのシナリオでは、データ変更の追跡も担当しますか? 私には、これは、作業単位がファイルを書き込む必要があるときにリポジトリがファイルを読み取ることができるが、ロジックが 2 つの場所に分割されていることを示唆しています。
4

5 に答える 5

33

リポジトリは Unit Of Work がなくても機能するため、Save メソッドを持つこともできます。

public interface IRepository<T>
{
     T Get(int id);
     void Add(T entity);
     void Update(T entity);
     void Remove(T entity);
     void Save();
}

Unit Of Work は、複数のリポジトリがある場合に使用されます (データ コンテキストが異なる場合があります)。Commit メソッドを呼び出してすべての変更をデータベース (この場合はファイル) に保持するまで、トランザクション内のすべての変更を追跡します。

そのため、リポジトリでAdd/Update/Removeを呼び出すと、エンティティのステータスが変更されるだけで、Added、Removed、または Dirty としてマークされます。Commit を呼び出すと、Unit Of Work はリポジトリをループし、実際の永続化を実行します。 :

  • リポジトリが同じデータ コンテキストを共有している場合、Unit Of Work はデータ コンテキストと直接連携してパフォーマンスを向上させることができます (この場合、ファイルを開いて書き込みます)。

  • リポジトリに異なるデータ コンテキスト (異なるデータベースまたはファイル) がある場合、作業単位は同じ TransactionScope で各リポジトリの Save メソッドを呼び出します。

于 2013-01-10T18:03:15.840 に答える
6

私は実際にはこれにかなり慣れていませんが、誰も投稿していないので:

CRUD がリポジトリで発生するコードは予想どおりですが、Account.Add (たとえば) が呼び出されると、Account オブジェクトが後で追加されるもののリストに追加されるだけです (変更は追跡されます)。 .

unitOfWork.Save() が呼び出されると、リポジトリは、変更されたもののリストまたは UoW の変更されたもののリスト (パターンの実装方法に応じて) を調べて、適切に動作することが許可されます。List<Account> NewItemsToAdd.Add() への呼び出しに基づいて、何を追加するかを追跡しているフィールドになります。UoW が保存してもよいと言うと、リポジトリは実際に新しいアイテムをファイルとして保持し、成功した場合は追加する新しいアイテムのリストをクリアします。

私の知る限り、UoW のポイントは、複数のリポジトリ間で保存を管理することです (これらを組み合わせることで、コミットしたい作業の論理単位になります)。

私はあなたの質問がとても好きです。Uow / Repository Pattern を Entity Framework で使用しましたが、EF が実際にどの程度実行するか (SaveChanges が最終的に呼び出されるまでコンテキストが変更を追跡する方法) を示しています。この設計パターンを例に実装するには、変更を管理するためにかなりの量のコードを記述する必要があります。

于 2013-01-10T17:33:40.390 に答える
4

ファイルシステムを使用すると、自分でそれを実行したい場合、非常に複雑になる可能性があります。

UoWがコミットされたときにのみ書き込みます。

あなたがしなければならないことは、リポジトリがUnitOfWorkのすべてのIO操作をキューに入れるようにすることです。何かのようなもの:

public class UserFileRepository : IUserRepository
{
    public UserFileRepository(IUnitOfWork unitOfWork)
    {
        _enquableUow = unitOfWork as IEnquableUnitOfWork;
        if (_enquableUow == null) throw new NotSupportedException("This repository only works with IEnquableUnitOfWork implementations.");

    }

    public void Add(User user)
    {
        _uow.Append(() => AppendToFile(user));
    }

    public void Uppate(User user)
    {
        _uow.Append(() => ReplaceInFile(user));
    }
}

そうすることで、すべての変更を同時にファイルに書き込むことができます。

DBリポジトリでこれを行う必要がない理由は、トランザクションサポートがDBに組み込まれているためです。したがって、DBにトランザクションを直接開始し、それを使用して作業単位を偽造するように指示できます。

トランザクションサポート

ファイルの変更をロールバックできる必要があり、同時にトランザクション中に異なるスレッド/トランザクションが同じファイルにアクセスするのを防ぐ必要があるため、複雑になります。

于 2013-01-14T06:29:03.527 に答える
4

ええ、物事はトリッキーです。このシナリオを想像してみてください: 1 つのレポはデータベースに何かを保存し、他のレポはファイル システムに保存し、3 番目のレポはクラウドに保存します。どうやってそれをコミットしますか?

ガイドラインとして、UoW は物事をコミットする必要がありますが、上記のシナリオでは、更新する 3 つの非常に異なるものがあるため、コミットは幻想にすぎません。結果整合性を入力します。これは、すべてのものが最終的に整合することを意味します (RDBMS を使用しているのと同じ瞬間ではありません)。

その UoW は、メッセージ駆動型アーキテクチャでは Saga と呼ばれます。ポイントは、すべてのサガ ビットを異なる時間に実行できることです。Saga は、3 つのリポジトリがすべて更新された場合にのみ完了します。

ほとんどの場合 RDBMS を使用するため、このアプローチはそれほど頻繁には見られませんが、最近では NoSql が非常に一般的であるため、従来のトランザクション アプローチは非常に限られています。

そのため、1 つの rdbms のみで作業することが確実な場合は、UoW でトランザクションを使用し、関連する接続を各リポジトリに渡します。最後に、UoW は commit を呼び出します。

複数の rdbms またはトランザクションをサポートしないストレージを使用する必要があることがわかっている、または予想される場合は、メッセージ駆動型アーキテクチャと saga の概念に慣れるようにしてください。

于 2013-01-11T08:25:16.377 に答える