我开始了解DDD,并关注从持久性中检索实体对象,然后在UI的视图模型中重新构建它们的性能影响。
假设我有两个聚合根:
Person Orders
------ -------
personId orderId
name personId
每个聚合根都有自己的存储库,负责整个聚合的基本CRUD操作。
假设UI需要以下列:
viewmodel
---------
personName
numberOfOrders
我可以想出两种方法来填充这个视图模型:
- 急切地加载所有个人实体,急切地加载基于personId的所有订单,将加载的实体重组到视图模型中
- 创建一个JOIN/COUNT(orderId)存储过程,并使数据库返回的数据与视图模型的结构相同
显然,选项1可能是相当昂贵的操作,因为可能会有多个人和多个订单导致多个数据库调用。选项2只需要一个数据库调用。
如果选项2是首选(性能)选项,那么我将这个"视图模型"和所谓的"数据库调用"存储在哪里?在我可以实现的存储库之上是否有一个单独的"数据服务层"?或者,就DDD的总体实施方式而言,这是一种反模式吗?
基本上,我如何协调复杂的DDD聚合和自定义UI视图模型,同时考虑性能?
更新
规范/查询对象
在与一位朋友的会谈中,他建议一种可能的解决方案是某种规范/查询对象模式。唯一的问题是,我们必须在存储库级别实现这一点,这需要我将人员和订单组合成一个大的集合。出于事务一致性的原因,我通常会避免这种情况。
您可以引入一个专用的值对象和一个存储库,该存储库将返回给定人员的统计信息:
// value object
class PersonStatistics {
String PersonName
Int NumberOfOrders
Money AverageOrderAmount
}
// repository
interface PersonStatisticsProvider {
PersonStatistics Get();
}
这类似于读取模型模式。
从性能的角度来看,我会选择选项2,但可能会将返回人员的查询与返回订单数量的查询分开。
您可以通过类似OrderRepository.GetOrderCountByPerson(personId)
的方式使订单计数可用,即使它确实偏离了您对存储库的规范定义。
通常从域实体派生ViewModels。如果有一个服务直接查询数据库,从而返回与ViewModel完全匹配的数据结构,这似乎很奇怪。