这取决于意见和用例,但我个人不同意你提到的一些关键点。
返回 IEnumerable 而不是 IQueryable
同意。返回IQueryable
违背了存储库存在的基本目的。网上有很多文章解释这如何产生更多问题而不是解决方案。尽管如此,我已经学会了永远不要说永远。参考this https://softwareengineering.stackexchange.com/q/192044/249896, this https://weblogs.asp.net/dotnetstories/repository-iqueryable, or this https://stackoverflow.com/q/33755499/5779732。或者直接搜索google https://www.google.co.in/search?q=repository+return+iqueryable.
存储库应仅负责 CRUD 操作
同意。通过简单的CRUD,它还可以进行复杂的读取和写入。我的经验告诉我,在特殊情况下,如果你想在RDBMS端实现它,你必须将部分业务逻辑放在存储库中。这没有对错。如果您知道自己在做什么,就不应该有问题。
存储库方法的返回类型应该是模型(实体)
如果您不使用 DDD,那么是的。否则,为执行决定。对于像 EF 或 NHibernate 这样的完整 ORM,最好直接返回域模型而不是每个表实体实例。
始终建议存储库应返回域模型。这样,从 RDBMS 返回的数据与域模型的映射(反之亦然)就成为存储库的责任。这避免了将持久性问题泄露到存储库之外的必要性,从而使应用程序持久性的其余部分一无所知。
但是,并不是每个应用程序都实现 DDD。许多小型应用程序设计的实体与其数据库设计一一对应。在这种情况下,存储库可能会返回实体(相当于您的表和字段)本身,并且映射成为调用代码的责任。或者,存储库可以映射必要的模型并返回模型本身。由于上述问题,强烈建议不要这样做。这样,您就必须放弃完整 ORM 提供的一些功能。
所有这一切都取决于您的问题是什么,您的设计目标是什么,应用程序的大小以及实施的其他设计模式等。这就是为什么它成为设计决策。
仅实现聚合根的存储库
如果是 DDD 则同意。如果没有,可以有多种选择,例如每个表存储库。同样,取决于用例。
关于复杂查询
存储库不必只实现简单的 CRUD 方法。它还可能返回复杂的对象图。它可能会进行复杂的查询。也就是说,用简单的方法,比如Get
, GetById
等等,它还可能消耗复杂的方法,例如GetTopBrokenVehicles(vehicleType, top)
。如果您为复杂查询编写单独的方法,那绝对没问题。
挑战在于,您如何接受必要的参数。您可以接受内联参数或构建单独的简单输入参数类。
这是示例代码存储库 https://stackoverflow.com/a/45460483/5779732 and UoW https://stackoverflow.com/a/45029588/5779732.