在通用存储库中使用IEnumerable <T>和IQueryable <T>
我已经阅读了一些关于实施通用知识库的文章。 我还阅读了一些解释从我的存储库中暴露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>
扩展方法。
请注意,选择哪些是基于编译时类型,而不是运行时类型。 因此,投射到IEnumerable
的IQueryable
将被视为IEnumerable
。 这与类通常的工作方式不同(多亏了多态性),但它允许呼叫站点控制如何执行这些操作。
一个有用的例子是,当你需要获得表中的所有记录,然后对它们进行计数。 无论如何你都要获得所有结果,不需要在SQL中执行计数。
链接地址: http://www.djcxy.com/p/62097.html上一篇: Using IEnumerable<T> and IQueryable<T> in a generic repository
下一篇: ends with (suffix) and contains string search using MATCH in SQLite FTS