9

ジェネリックリポジトリの実装に関する多くの投稿を読みました。また、リポジトリから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ているので、私が知りたいのは、これが汎用インターフェースでどのように機能するかです。

  1. IQueryable<T>から派生しIEnumerable<T>ます。私のfindメソッドではIQueryable<T>オブジェクトを返していますが、クライアントはこれを。としてのみ認識しますIEnumerable<T>。これは、オブジェクトに対して後続のクエリをIEnumerable<T>実行すると、実際にデータベースで操作を実行し、結果のみを返すことを意味します(この場合、オブジェクトはである IQueryableため)。または、
  2. Whereメソッドに渡された句のみがFindデータベースで実行され、オブジェクトで実行される後続のクエリはすべてIEnumerable<T>クライアントで実行されます。または、
  3. これらのどちらも起こりません、そして私は完全にどのようIEnumarable<T>に、IQueryable<T>そしてLinq働くかを誤解しました。

アップデート:

コメントで受け取った回答には、実際にはかなり驚いています。私の元のリポジトリはIQueryableを返し、その後の調査により、これは悪いことだと思いました(たとえば、viewModelがコンストラクタでリポジトリを受け入れる場合、必要なクエリを呼び出すことができるため、テストがより困難になります)。

これまでに見たすべてのソリューションには、IQueryableが公開されないようにエンティティ固有のリポジ​​トリを作成することが含まれます(私が推測する唯一の違いは、これを一般的な方法で行っていることです)。

4

1 に答える 1

6

返されるのでIEnumerable<T>、後続のすべての呼び出しはメモリ内で(ローカルで)実行されます。

覚えておくべきことの1つは、LINQが一連の拡張メソッドで動作することです。IQueryable<T>ローカル以外の場所でクエリを実行するために必要なすべての配線をサポートする拡張メソッドと、ローカルでのみ機能する拡張メソッドがありますIEnumerable<T>

これらのどれが選択されるかは、実行時タイプではなく、コンパイル時タイプに基づいていることに注意してください。したがって、IQueryableにキャストされたIEnumerableは、として扱われますIEnumerable。これは、クラスが通常機能する方法とは異なりますが(ポリモーフィズムのおかげで)、呼び出しサイトがこれらの操作を実行する方法を制御できます。

これが役立つ例は、テーブル内のすべてのレコードを取得してからそれらをカウントする必要がある場合です。とにかくすべての結果を取得する場合は、SQLでカウントを実行する必要はありません。

于 2012-07-31T19:00:08.017 に答える