[英]Using IEnumerable<T> and IQueryable<T> in a generic repository
我已经阅读了一些关于通用存储库实现的帖子。 我还阅读了一些帖子,解释了从我的存储库中暴露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
)? 要么, Find
方法的Where
子句,并且在客户端上执行在IEnumerable<T>
对象上执行的任何后续查询。 要么, IEnumarable<T>
, IQueryable<T>
和Linq
工作的。 更新:
实际上,我对评论中收到的答案感到非常惊讶。 我的原始存储库返回IQueryable并且随后的研究使我相信这是一件坏事(例如,如果我的viewModel在其构造函数中接受了一个存储库,它可以调用它想要的任何查询,这使得它更难以测试)。
到目前为止,我所看到的所有解决方案都涉及创建特定于实体的存储库,以便不暴露IQueryable(我猜的唯一区别是我以通用方式执行此操作)。
因为您正在返回IEnumerable<T>
所有后续调用都将在内存(本地)中完成。
要记住的一件事是LINQ使用一组扩展方法。 IQueryable<T>
有扩展方法,它支持在本地以外的位置执行查询所需的所有连接,以及IEnumerable<T>
扩展方法,它们只在本地工作。
请注意,选择了哪一个基于编译时类型,而不是运行时类型。 因此, IQueryable
转换为IEnumerable
的IQueryable
将被视为IEnumerable
。 这与类通常工作的方式不同(多亏了多态)但是它允许调用站点控制如何执行这些操作。
这有用的一个例子是当你需要获取表中的所有记录然后对它们进行计数时。 如果要获得所有结果,则无需在SQL中执行计数。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.