存储库/ IQueryable /查询对象

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

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

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

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

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

例如public IEnumerable FindBy(Query query)

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

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

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

只需返回一个IQueryable

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

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

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

关于你的两个问题,

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

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

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

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

 interface IPersonRepository { Person GetById(int id); IEnumerable FindByName(string firstName, string lastName); } 

与之相反

 interface IRepository { IEnumerable FindBy(Query query); } 

此外,你真的可以指出使用IRepository的好处(而不是IQueryable )吗?

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

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

与上面的统治答案相反,明确的反对点是unit testing 。 返回一个简单的genericsIQueryable是任何有权调用它的客户端的漏洞抽象。 因此,对于存储库方法没有限制,在unit testing中无需断言。

IQueryable的使用几乎肯定取决于应用程序本身的上下文和体系结构。 例如,如果你自己做个人项目,你可以安全地承担起使用这种不受限制的权力的责任,而不会诅咒除了你自己以外的任何人。 但是,如果您正在为一家代码投入生产的公司开发应用程序,那么肯定会有比您更多的利益相关者。 在这种情况下,您可能正在数据访问层中工作并尝试对其他开发人员使用您的代码进行编码。 现在你需要控制进出的内容,这样它们就不会破坏你的代码,你也不会破坏它们。 这是激励,unit testing就是强制执行。

话虽如此,不要简单地使用IQueryable使用对您的应用程序有意义的东西。