我有一个存储库类,它包装了我的LINQ to SQL数据上下文.存储库类是一个业务线类,包含所有数据层逻辑(以及缓存等).
这是我的repo界面的v1.
public interface ILocationRepository { IListFindAll(); IList FindForState(State state); IList FindForPostCode(string postCode); }
但是为了处理FindAll的分页,我正在讨论是否要公开IQueryable
从数据仓库中暴露IQueryable的利弊是什么?
很感谢任何形式的帮助.
专业人士; 可组合:
呼叫者可以添加过滤器
呼叫者可以添加分页
呼叫者可以添加排序
等等
缺点; 非可测性:
您的存储库不再适用于单元可测试; 你不能依赖:它工作,b:它做什么 ;
调用者可以添加一个不可翻译的函数(即没有TSQL映射;在运行时中断)
调用者可以添加一个过滤器/排序,使其像狗一样运行
由于调用者希望IQueryable
是可组合的,它排除了不可组合的实现 - 或者它迫使你为它们编写自己的查询提供者
这意味着您无法优化/分析DAL
为了稳定,我已经采取不暴露IQueryable
或Expression<...>
在我的存储库.这意味着我知道存储库的行为方式,而我的上层可以使用模拟而不用担心"实际的存储库是否支持这个?" (强制集成测试).
我仍然使用IQueryable
等内部信息库-但不下来的边界.我在这里发表了关于这个主题的更多想法.将分页参数放在存储库接口上同样容易.您甚至可以使用扩展方法(在接口上)添加可选的分页参数,这样具体类只有1个方法可以实现,但调用者可能有2或3个重载.
正如前面的回答所提到的,暴露IQueryable可以让调用者可以使用IQueryable本身,这可能会变得很危险.
封装业务逻辑的首要任务是保持数据库的完整性.
您可以继续公开IList,可能会更改您的参数如下,这就是我们正在做的事情......
public interface ILocationRepository { IListFindAll(int start, int size); IList FindForState(State state, int start, int size); IList FindForPostCode(string postCode, int start, int size); }
如果size == -1则返回all ...
替代方式......
如果您仍想返回IQueryable,那么您可以在函数内返回List的IQueryable ..例如......
public class MyRepository { IQueryableFindAll() { List myLocations = ....; return myLocations.AsQueryable ; // here Query can only be applied on this // subset, not directly to the database } }
第一种方法优于内存,因为您将返回较少的数据而不是全部.