ジェネリックリポジトリの実装に関する多くの投稿を読みました。また、リポジトリからIEnumerableとIQueryableを公開することの違いを説明する多数の投稿を読みました。
データを(クライアントによってメモリではなく)データベースでフィルタリングできる柔軟性が必要ですが、すべてのエンティティ(およびそれらのインターフェイスを実装する具象クラス)に対して個別のリポジトリインターフェイスを定義する必要はありません。
これまでのところ、私のリポジトリは次のようになっています。
public interface IRepository<T>
{
IEnumerable<T> GetAll();
IEnumerable<T> Find(Expression<Func<T, bool>> where);
void Add(T entity);
void Attach(T entity);
void Delete(T entity);
}
具体的な実装の例は次のとおりです。
public class Repository<T> : IRepository<T> where T : class
{
private DbContext _context;
private DbSet<T> _entitySet;
public Repository(DbContext context)
{
_context = context;
_entitySet = _context.Set<T>();
}
public IEnumerable<T> GetAll()
{
return _entitySet;
}
public IEnumerable<T> Find(Expression<Func<T, bool>> where)
{
return _entitySet.Where(where);
}
public void Add(T entity)
{
_entitySet.Add(entity);
}
public void Attach(T entity)
{
_entitySet.Attach(entity);
}
public void Delete(T entity)
{
_entitySet.Remove(entity);
}
}
この場合、私のリポジトリは使用しDbContext
ているので、私が知りたいのは、これが汎用インターフェースでどのように機能するかです。
IQueryable<T>
から派生しIEnumerable<T>
ます。私のfindメソッドではIQueryable<T>
オブジェクトを返していますが、クライアントはこれを。としてのみ認識しますIEnumerable<T>
。これは、オブジェクトに対して後続のクエリをIEnumerable<T>
実行すると、実際にデータベースで操作を実行し、結果のみを返すことを意味します(この場合、オブジェクトはであるIQueryable
ため)。または、Where
メソッドに渡された句のみがFind
データベースで実行され、オブジェクトで実行される後続のクエリはすべてIEnumerable<T>
クライアントで実行されます。または、- これらのどちらも起こりません、そして私は完全にどのよう
IEnumarable<T>
に、IQueryable<T>
そしてLinq
働くかを誤解しました。
アップデート:
コメントで受け取った回答には、実際にはかなり驚いています。私の元のリポジトリはIQueryableを返し、その後の調査により、これは悪いことだと思いました(たとえば、viewModelがコンストラクタでリポジトリを受け入れる場合、必要なクエリを呼び出すことができるため、テストがより困難になります)。
これまでに見たすべてのソリューションには、IQueryableが公開されないようにエンティティ固有のリポジトリを作成することが含まれます(私が推測する唯一の違いは、これを一般的な方法で行っていることです)。