UnitOfWork と Repository のどちらを巡るかについて、多くの投稿 (および議論!) を見てきました。私が好むレポジトリ パターンの 1 つは、型付きの汎用レポジトリ パターンですが、これにより、クリーンなコードとテスト容易性に関するいくつかの問題が発生したのではないかと心配しています。次のリポジトリ インターフェイスとジェネリック クラスを使用します。
public interface IDataEntityRepository<T> : IDisposable where T : IDataEntity
{
// CRUD
int Create(T createObject);
// etc.
}
public class DataEntityRepository<T> : IDataEntityRepository<T> where T : class, IDataEntity
{
private IDbContext Context { get; set; }
public DataEntityRepository (IDbContext context)
{
Context = context;
}
private IDbSet<T> DbSet { get { return Context.Set<T>(); } }
public int Create(T CreateObject)
{
DbSet.Add(createObject);
}
// etc.
}
// where
public interface IDbContext
{
IDbSet<T> Set<T>() where T : class;
DbEntityEntry<T> Entry<T>(T readObject) where T : class;
int SaveChanges();
void Dispose();
}
したがって、基本的には各パターンで Context プロパティを使用して、基になるコンテキストにアクセスしています。私の問題は次のとおりです。作業単位を作成すると、それは事実上、リポジトリに知ってもらいたいコンテキストのラッパーになります。したがって、次のように宣言する Unit Of Work があるとします。
public UserUnitOfWork(
IDataEntityRepository<User> userRepository,
IDataEntityRepository<Role> roleRepository)
{
_userRepository = userRepository;
_roleRepository = roleRepository;
}
private readonly IDataEntityRepository<User> _userRepository;
public IDataEntityRepository<User> UserRepository
{
get { return _userRepository; }
}
private readonly IDataEntityRepository<Role> _roleRepository;
public IDataEntityRepository<Role> RoleRepository
{
get { return _roleRepository; }
}
私が渡している2つのリポジトリは、それらが渡されている作業単位でインスタンス化する必要があるという事実に問題があります。明らかに、コンストラクター内でリポジトリをインスタンス化して「this」を渡すこともできますが、それでは私の作業単位がリポジトリの特定の具体的なインスタンスに緊密に結合され、単体テストがはるかに難しくなります。他の誰かがこの道を進んで同じ壁にぶつかったかどうか知りたいです。これらのパターンはどちらも私にとって初めてのことなので、根本的に間違ったことをしている可能性があります。どんなアイデアでも大歓迎です!
更新 (@MikeSW への応答)
こんにちはマイク、ご意見をお寄せいただきありがとうございます。私は EF Code First を使用していますが、特定の要素を抽象化して、必要に応じて別のデータ ソースまたは ORM に切り替えることができるようにしたいと考えていました。特定の要素は純粋な意味で単体テストできないが、統合テストはできるという難しい方法に気付いたと思います! ビジネス オブジェクトやビューモデルなどを操作するリポジトリについてのポイントを上げたいと思います。おそらく誤解しているかもしれませんが、私のコア ビジネス オブジェクト (POCO) と見なされるものがあり、EF コードなどの ORM を使用したい場合最初にこれらのエンティティをラップして、データベースを作成してから操作します (そして、ViewModel 内でこれらのエンティティを再利用する可能性があります)。リポジトリは、一連の CRUD 操作のコンテキストでこれらのエンティティを直接処理することを期待しています。エンティティは、永続化レイヤーについて何も認識していません。ViewModel も認識していません。私の作業単位は、必要なリポジトリをインスタンス化して保持するだけで、トランザクションのコミットを実行できます (複数のリポジトリにまたがるが、同じコンテキスト/セッション)。私のソリューションで行ったことは、UnitOfWork コンストラクターから IDataEntityRepository の注入を削除することです。 、実際には EFDataEntityRepository のような名前にする必要があります)。ユニットロジック全体が、データベースへのコンテキスト(自体)を使用してリポジトリを確立することになるため、これ自体をユニットテストすることはできません。単に統合テストが必要です。それが理にかなっていることを願っていますか?!