我已经阅读了许多关于实现通用存储库的帖子。我还阅读了许多帖子,这些帖子解释了从我的存储库中公开 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>
对象执行任何后续查询,它实际上会在数据库上执行操作并且只返回结果(因为在这种情况下对象是 aIQueryable
)?或者,- 只有
Where
传入方法的子句在数据库上执行,对对象执行的Find
任何后续查询都在客户端上执行。IEnumerable<T>
或者, - 这些都没有发生,我完全误解了它是如何
IEnumarable<T>
工作IQueryable<T>
的Linq
。
更新:
我实际上对我在评论中收到的答案感到相当惊讶。我的原始存储库返回了 IQueryable,随后的研究让我相信这是一件坏事(例如,如果我的 viewModel 在其构造函数中接受了一个存储库,它可以调用它想要的任何查询,这使得测试变得更加困难)。
到目前为止,我为此看到的所有解决方案都涉及创建特定于实体的存储库,以便不暴露 IQueryable(我猜唯一的区别是我以通用方式执行此操作)。