11

私は、さまざまなデータストアに対して機能する汎用リポジトリを作成する方法を考え出そうとしてきました。

public interface IRepository
{
    IQueryable<T> GetAll<T>();
    void Save<T>(T item);
    void Delete<T>(T item);
}
public class MemoryRepository : IRepository {...}
public class SqlRepository : IRepository {...}

それぞれの同じPOCOドメインクラスに対して作業したいと思います。同様のアプローチも検討しています。各ドメインクラスには独自のリポジトリがあります。

public interface IRepository<T>
{
    IQueryable<T> GetAll();
    void Save(T item);
    void Delete(T item);
}
public class MemoryCustomerRepository : IRepository {...}
public class SqlCustomerRepository : IRepository {...}

私の質問:1)最初のアプローチは実行可能ですか?2)2番目のアプローチに利点はありますか?

4

3 に答える 3

5
  1. 最初のアプローチは実行可能です。以前、RDBMS とXmlWriter/を対象とする独自のマッピング フレームワークを作成したときに、似たようなことを行いましたXmlReader。この種のアプローチを使用して単体テストを容易にすることができますが、今ではそれを行うための優れた OSS ツールがあると思います。

  2. 2 番目のアプローチは、私が現在IBATIS.NET マッパーで使用しているものです。すべてのマッパーにはインターフェースがあり、すべてのマッパーは基本的な CRUD 操作を提供できます。利点は、ドメイン クラスの各マッパーには、インターフェイスによって表現され、具体的なマッパーで定義される特定の関数 ( や など) があることですSelectByLastNameDeleteFromParentこのため、あなたが提案しているように、私が個別のリポジトリを実装する必要はありません。具体的なマッパーはデータベースをターゲットにしています。単体テストを実行するために、StructureMapMoqを使用してメモリ内リポジトリを作成します。Memory*Repositoryします。実装および管理するクラスが少なくなり、全体的な作業が少なくなり、非常にテストしやすいアプローチになります。単体テスト間で共有されるデータについては、WithXXXメソッドとAsSomeProfileメソッドを持つドメイン クラスごとにビルダー パターンを使用します (AsSomeProfile事前に構成されたテスト データを含むビルダー インスタンスを返すだけです)。

これは、ユニットテストで通常終了するものの例です。

// Moq mocking the concrete PersonMapper through the IPersonMapper interface
var personMock = new Mock<IPersonMapper>(MockBehavior.Strict);
personMock.Expect(pm => pm.Select(It.IsAny<int>())).Returns(
    new PersonBuilder().AsMike().Build()
);

// StructureMap's ObjectFactory
ObjectFactory.Inject(personMock.Object);

// now anywhere in my actual code where an IPersonMapper instance is requested from
// ObjectFactory, Moq will satisfy the requirement and return a Person instance
// set with the PersonBuilder's Mike profile unit test data
于 2008-11-07T04:04:26.467 に答える
2

これは少し遅れています... しかし、codeplex のCommonLibrary.NETで IRepository の実装を見てください。かなり優れた機能セットを備えています。

あなたの問題に関しては、多くの人がリポジトリの実装で GetAllProducts()、GetAllEmployees() などのメソッドを使用しているのを目にします。これは冗長であり、リポジトリを汎用にすることはできません。必要なのは GetAll() または All() だけです。ただし、上記の解決策は命名の問題を解決します。

これは、オンラインの CommonLibrary.NET ドキュメントから取得したものです。

0.9.4 Beta 2 には強力なリポジトリ実装があります。

* Supports all CRUD methods ( Create, Retrieve, Update, Delete )
* Supports aggregate methods Min, Max, Sum, Avg, Count
* Supports Find methods using ICriteria<T>
* Supports Distinct, and GroupBy
* Supports interface IRepository<T> so you can use an In-Memory table for unit-testing
* Supports versioning of your entities
* Supports paging, eg. Get(page, pageSize)
* Supports audit fields ( CreateUser, CreatedDate, UpdateDate etc )
* Supports the use of Mapper<T> so you can map any table record to some entity
* Supports creating entities only if it isn't there already, by checking for field values.
于 2010-03-10T17:20:05.723 に答える