有一个有争议的讨论Repositories,它们在stackoverflow和整个网络上的使用和布局。我对如何有效地实现存储库后面的数据访问抽象(例如数据库)感到困惑。
我没有使用ORM工具/框架,因为我希望自己看到细节。目前我正在使用DAO对象访问(mysql)数据库并提供Business Objects(域对象)。由数据库表中的外键给出的关联被解析并加载到相应对象的DAO中(当前没有延迟加载)。由于我不想直接在业务逻辑中使用我的数据库DAO,因此我认为存储库是一个很好的进一步抽象。在存储库中实现像 GetEmployeesByShopAndPosition()这样的复杂查询时,我遇到了困难:我看到了实现这个的两种可能性:
第一种方法使用了存储库实际应具有的集合性质,但似乎非常低效。第二种方法生成bloated DAO,但效率更高。
我的问题:
我知道这个主题不是黑/白,因为所涉及的设计模式也可以以不同的方式实现,但我想有一些指导方针不应该被打破或混淆以分离关注点和持久性无知(PI)
答案 0 :(得分:5)
你实际上在这里提出了很多问题所以我会尽量保持答案的简洁:)
存储库返回Aggregate Root
或Entity
。有些人非常坚定认为存储库只能返回AR,这很好并且总是足够的。
有两种类型的存储库(Vaughn Vernon在他的实现领域驱动设计一书中很好地描述了它):
您可能会遇到并更频繁地使用面向持久性的方法。这可能是w.r.t中出现混乱的地方。 DAO。当然,DAO可以返回一个业务对象,但它可能会返回更多。
您的查询示例是DAO可能更合适的地方。因此,在域驱动设计领域,您会经常遇到CQRS(命令/查询责任隔离)。归结为不查询您的域名。
您应该拥有一个精简的,专用的查询图层,以最合适的格式(但不是实体)返回结果。在c#中,我使用的内容包括DataTable
,DataRow
,string
,有时还需要复杂的DTO。
存储库仅涉及AR,例如:
存储库基本上使用各种逻辑DAO(ADO.NET,ORM ---我尽量避免使用ORM)。
关于检索具有相关外键的AR的第二位:AR应该从不包含对另一个AR的引用。实体和Value Objects
都很好。对于关联的AR,使用ID或值对象来表示外来AR。 AR可能由一个复杂的结构本身组成,但不要将所有权与遏制混淆。 OrderLine
中包含Order
。 Customer
拥有Order
。因此Order
将拥有OrderLine
集合,但不会引用Customer
对象(而非ID / VO)。
Order
/ OrderLine
示例说明了我们不查询域名的原因。当我们想要一个给定的开始和结束日期之间的订单列表时,我们可能不会对所有订单数据感兴趣,当然也不会对订单行感兴趣。因此加载这些聚合没有任何意义。这是在查询域时,懒惰加载等令人讨厌的东西蔓延。懒惰加载不应该存在恕我:) :)一个简单的查询层就足够了。
希望有所帮助。
答案 1 :(得分:1)
尽可能使用数据库的强大功能。这就是ORM会尝试做的事情 - 在SQL查询中尽可能多地进行过滤,排序等。
我认为同时拥有存储库和DAO都没什么价值。它们都抽象出持久存储。如果您想要没有ORM,您通常会在具体的Repository实现中处理数据库查询生成部分。但在协作应用程序中,这也会留下其他复杂的东西,例如变更跟踪,事务管理等。
完整的整体聚合,是的。但作为建模良好实践,尽量不要存储(并因此重新水化)对聚合中其他聚合根的引用。
这是从“经典”DDD的角度来看,但是如果你想要去CQRS路线(有些人会说它是唯一明智的路线;),请务必遵循@ EbenRoux的建议。