存储库/ IQueryable /查询对象

Dal*_*e K 18 c# iqueryable repository-pattern objectquery

我正在构建一个存储库,我在很多地方看到过2个不在存储库外暴露IQueryable的原因.

1)首先是因为不同的LINQ提供程序可能表现不同,这种差异应该包含在存储库中.

2)第二是防止服务级别开发人员修改数据库查询,以免意外导致性能问题.

我想问题2只能通过将所有查询逻辑保留在存储库中并且不允许任何形式的外部查询构建来防止?但这对我来说似乎有点不切实际.

问题1似乎可以通过使用数据对象模式来解决.

例如 public IEnumerable<T> FindBy(Query query)

我的问题是,为什么我不仅仅传递一个lambda表达式,因为它与提供者无关,似乎为我提供了与查询对象相同的功能,以及相同的分离级别?

例如 public IEnumerable<T> FindBy(Expression<Func<T,bool>> predicate)

有什么理由不这样做吗?它违反了一些规则吗?最佳做法?我应该知道什么?

sma*_*man 21

回来吧IQueryable<T>.

在您编写另一部分"存储库代码"之前,您将从阅读Ayende的文章"毁灭之坑中的建筑 - 存储库抽象层的邪恶 "中获益匪浅

毫无疑问,您的方法会增加不必要的复杂性.

来自OrderBy Lambda的通用列表中的另一个问题的所有代码除了使用不必要且不熟悉的抽象掩盖现有的有效API之外,不能做任何事情.

关于你的两个问题,

  1. LINQ提供程序的行为有所不同,但只要您传递的谓词可以由LINQ提供程序处理,这是无关紧要的.否则,你仍然会遇到同样的问题,因为你传入了一个Expression,IQueryable无论如何都会传递给最终.如果IQueryProvider实现无法处理您的谓词,那么它无法处理您的谓词.(ToList()如果您需要在进一步过滤之前进行评估,则无法翻译,您可以随时调用a ).

  2. 修改查询可能会导致性能问题,但更有可能暴露出急需的功能.此外,次优LINQ查询引起的性能问题可能比通过提取比您需要的更多记录而产生的性能问题明显更不利,以避免暴露IQueryable或通过系统过滤任何数据访问逻辑实际上没有做任何事情的抽象级别(第一个威胁更重要).通常,这不会成为问题,因为大多数领先的LINQ提供程序将在翻译过程中优化您的查询逻辑.

如果要从前端隐藏查询逻辑,请不要尝试创建通用存储库.使用实际的业务特定方法封装查询.现在,我可能会弄错,但我假设您使用存储库模式的灵感来自Domain Driven Design.如果是这种情况,那么使用存储库的原因是允许您创建一个主要关注域模型的持久性无知域.但是,使用这种通用存储库并不比将语义更改Create Read Update Delete为更多Find Add Remove Save.那里没有任何真正的商业知识.

考虑一下的意义(和可用性)

interface IPersonRepository 
{ 
     Person GetById(int id);
     IEnumerable<Person> FindByName(string firstName, string lastName);
}
Run Code Online (Sandbox Code Playgroud)

相比之下

interface IRepository<T> { 
     IEnumerable<T> FindBy(Query<T> query);
}
Run Code Online (Sandbox Code Playgroud)

此外,你真的可以指出使用IRepository<T>根本(而不是一个IQueryable<T>)的好处吗?

另外,考虑到使用通用方法,您根本不会实际封装查询逻辑.您最终会在外部构建它,这将导致更多不必要的代码.

*关于建议不使用资源的另一个注意事项IQueryable<T>是,值得查看其出版日期.曾经有一段时间LINQ提供程序的可用性非常有限(早期的EF和LINQ-to-SQL).在那个时候暴露一个IQueryable<T>将导致与一些微软ORM更受欢迎的替代品不兼容(LINQ-to-NHibernate早已实现).在这个时间点,LINQ支持在严重的ORM .NET库中几乎无处不在

  • 使用Repository模式的一个好处是数据源管理(上下文等)可以封装在存储库中.否则,使用查询的客户端必须将上下文传递给查询本身,使客户端"知道太多".此外,存储库非常适合存储特定于上下文的详细信息或写入操作. (5认同)
  • 作为开发人员,我们永远不会忘记数据库,EF不是一个神奇的子弹.如果需要在NoSQL中存储UnitOfWork数据或从SAP服务获取数据,那么IQueryable在哪里?或者使用存储过程优化呢?想一想的文章http://developersdev.blogspot.ru/2013/12/iquerable-drawbacks-repository-pattern.html (2认同)