只需返回一个IQueryable<T>
.
在你再写一点“存储库代码”之前,你会从阅读 Ayende 的文章Architecting in the Pit of Doom - The Evils of the Repository Abstraction Layer 中受益匪浅
毫无疑问,您的方法会增加不必要的复杂性。
Generic List of OrderBy Lambda中其他问题的所有代码除了用不必要和不熟悉的抽象来掩盖现有的有效 API 之外,没有做任何事情。
关于你的两个担忧,
LINQ 提供程序的行为确实不同,但只要您传递的谓词可以由 LINQ 提供程序处理,这无关紧要。否则,您仍然会遇到同样的问题,因为您传递的是 an ,无论如何Expression
它最终都会传递给。IQueryable
如果IQueryProvider
实现不能处理你的谓词,那么它就不能处理你的谓词。ToList()
(如果您需要在无法翻译的进一步过滤之前进行评估,您可以随时调用)。
修改查询可能会导致性能问题,但更可能会暴露急需的功能。此外,次优 LINQ 查询引起的性能问题可能比拉取比您需要的多得多的记录所引起的性能问题的危害要小得多,以避免暴露IQueryable
或系统地过滤任何数据访问逻辑通过臃肿实际上不做任何事情的抽象级别(第一个威胁更重要)。通常,这不会成为问题,因为大多数领先的 LINQ 提供程序都会在翻译过程中优化您的查询逻辑。
如果您想从前端隐藏查询逻辑,请不要尝试创建通用存储库。用实际的业务特定方法封装查询。现在,我可能弄错了,但我假设您对存储库模式的使用受到领域驱动设计的启发。如果是这种情况,那么使用存储库的原因是允许您创建一个主要关注域模型的持久性无知域。但是,使用这种通用存储库只会将您的语义从 更改Create Read Update Delete
为Find Add Remove Save
. 那里没有嵌入任何真正的商业知识。
考虑一个项目的意义(和可用性)
interface IPersonRepository
{
Person GetById(int id);
IEnumerable<Person> FindByName(string firstName, string lastName);
}
与
interface IRepository<T> {
IEnumerable<T> FindBy(Query<T> query);
}
此外,您实际上可以指出使用IRepository<T>
at 的好处(而不是 a IQueryable<T>
)吗?
此外,考虑到使用通用方法,您实际上根本没有封装查询逻辑。你最终在外部构建它,这将导致更多额外的不必要的代码。
*关于建议不要使用的资源的另一个注意事项IQueryable<T>
是,值得查看它们的发布日期。曾经有一段时间,LINQ 提供程序的可用性非常有限(对于早期的 EF 和 LINQ-to-SQL)。那时,暴露一个IQueryable<T>
将导致与 Microsoft ORM 的一些更流行的替代品不兼容(LINQ-to-NHibernate 早已实现)。目前,LINQ 支持在严肃的 ORM .NET 库中几乎无处不在