如何在不将IQueryable暴露给我的应用程序的其余部分的情况下编写一个干净的存储库?

mmc*_*ole 19 iqueryable repository repository-pattern linq-to-sql

所以,我已经阅读了所有关于是否将IQueryable暴露给你项目的其余部分的问题所在的问题(见这里这里),我最终决定我不想要将IQueryable暴露给我的模型以外的任何东西.因为IQueryable与某些持久性实现有关,所以我不喜欢将自己锁定在其中的想法.同样,我不确定我对调用链中的类进一步修改不在存储库中的实际查询的感觉有多好.

那么,有没有人有任何关于如何编写一个干净简洁的存储库而不这样做的建议?我看到的一个问题是,我的存储库将从大量方法中爆炸,我需要过滤掉我的查询.

有一堆:

IEnumerable GetProductsSinceDate(DateTime date);  
IEnumberable GetProductsByName(string name);  
IEnumberable GetProductsByID(int ID);
Run Code Online (Sandbox Code Playgroud)

如果我允许传递IQueryable,我可以很容易地拥有一个看起来像这样的通用存储库:

public interface IRepository<T> where T : class
{
    T GetById(int id);
    IQueryable<T> GetAll();
    void InsertOnSubmit(T entity);
    void DeleteOnSubmit(T entity);
    void SubmitChanges();
}
Run Code Online (Sandbox Code Playgroud)

但是,如果你没有使用IQueryable,那么像GetAll()这样的方法并不实用,因为延迟评估不会发生.我不想只返回10,000条记录,以后再使用其中的10条.

这是什么答案?在Conery的MVC店面中,他创建了另一个名为"服务"层的层,该层从存储库接收了IQueryable结果,并负责应用各种过滤器.

这是我应该做的,或类似的东西?让我的存储库返回IQueryable但是通过将其隐藏在一堆过滤器类(如GetProductByName)后限制对它的访问,这将返回像IList或IEnumerable这样的具体类型?

Ven*_*emo 5

公开一个IQueryable是一个非常可行的解决方案,这就是现在大多数Repository实现的方法.(包括SharpArchitecture和FubuMVC contrib.)

这是你错的地方:

但是,如果你没有使用IQueryable,那么像GetAll()这样的方法并不实用,因为延迟评估不会发生.我不想只返回10,000条记录,以后再使用其中的10条.

这不是真的.您的示例是正确的,您应该将GetAll()重命名为更具信息性的名称.

如果你打电话,它不会返回所有项目.这就是IQueryable的用途.该概念称为"延迟加载",因为它只在您枚举时加载数据(并生成数据库请求)IQueryable.

所以,假设我有一个像这样的方法:

IQueryable<T> Retrieve() { ... }
Run Code Online (Sandbox Code Playgroud)

然后,我可以这样称呼它:

Repository.Retrieve<Customer>().Single(c => c.ID == myID);
Run Code Online (Sandbox Code Playgroud)

这只能从数据库中检索一行.

还有这个:

Repository.Retrieve<Customer>().Where(c => c.FirstName == "Joe").OrderBy(c => c.LastName);
Run Code Online (Sandbox Code Playgroud)

这也会生成相应的查询,只有在枚举时才会执行.(它从查询中生成表达式树,然后查询提供程序应将其转换为针对数据源的适当查询.)

您可以在此MSDN文章中阅读有关它的更多信息.

  • 我认为这也是他所理解的.他说的是,当你__不使用`IQueryable`而是使用`IEnumerable`作为GetAll时,即使你只使用10,你也会得到所有. (5认同)