【问题标题】:Fetching associated aggregates in Domain driven Design在领域驱动设计中获取关联的聚合
【发布时间】:2016-08-06 06:51:09
【问题描述】:

我最近开始探索领域驱动设计并有一个问题。假设我的应用程序中有一个产品、类别、制造商域模型。产品看起来像这样:

public class Product 
{ 
int ProductId; 
string Title; 
string Description; 
double Price; 
int CategoryId; 
Category Category; 
Manufacturer Manufacturer; 
}

通常在显示产品的详细视图中,会显示类别名称和制造商名称(而不是其 ID)。但是类别和制造商是不同的聚合。问题是如何获取制造商和类别名称以及产品域模型。 ProductRepository 将仅返回产品域模型(以及 categoryId 和 ManufacturerId)。

  1. 我的产品服务提出另一个请求以获取 CategoryId 和 ManufacturerId
  2. 或者我可以在从产品存储库中获取产品时获取它们。

但我不需要所有属性,我只需要它们的标题。我在所有领域模型中都面临着类似的问题。

请帮助我应该如何解决这个问题。

【问题讨论】:

    标签: domain-driven-design


    【解决方案1】:

    您可以通过多种方式处理此问题:

    本地缓存/视图模型

    在您的服务中本地保留一个内存缓存,该缓存在 CategoryId 和 CategoryTitle(制造商相同)之间映射 - 这可以通过:

    • 监听事件(即 CategoryCreated)。如果您有一个事件驱动的系统,这将是首选。如果相关,您还可以收听其他事件(即 CategoryTitleUpdated)。
    • 通过向外部服务发出 Web 请求。您将首先查询本地缓存,然后决定是否调用外部服务。您需要考虑您的缓存会变得多么陈旧。

    非规范化数据

    您可以通过将 CategoryTitle 与 CategoryId 一起保存来复制数据。这样您就无需调用外部服务。权衡是您需要考虑 CategoryTitle 可能更改的频率,以及您如何处理该更改。

    报告“域”

    您可以拥有一个完全独立的服务来侦听来自其他服务的数据并维护 UI 的视图模型。这将使您的其他服务不知道其他服务的担忧。使用事件驱动系统时,您将监听来自其他服务的事件,这些服务允许您为 UI 构建视图模型

    【讨论】:

      【解决方案2】:

      通常在显示产品的详细视图中,会显示类别名称和制造商名称(而不是其 ID)。 ...问题是如何获取制造商和类别名称以及产品域模型。 ProductRepository 只会返回产品域模型(以及 categoryId 和 ManufacturerId)

      如我所见,类别名称和制造商名称用于显示,因此它是演示问题。 我建议为仅服务于该屏幕的 Product 设置一个单独的读取模型(请参阅 Command Query Responsibility Segregation (CQRS)):

      public class ProductReadModel 
      { 
          int ProductId; 
          string Title; 
          string Description; 
          double Price; 
          string CategoryName; 
          string ManufacturerName; 
      }
      

      有不同的方法来填充/构建该模型:

      • 如果我们的聚合使用 ORM(例如 NHibernate)保存在关系数据库中,那么您可以使用原始 SQL 或轻量级 ORM(例如 Dapper)直接查询您的数据库。你不需要它的存储库,你只需要 QueryHandler

      • 1234563记忆)。
      • 如果您的聚合保存在关系数据库中,您还可以触发和投影/非规范化域事件。

      【讨论】:

      • 感谢 IIya 的回复!如果我开始使用 Read model for detail page,我在我的应用程序中看不到 DomainModel 的太多使用。列表页面还将获取“读取模型”以及详细信息页面。只有在创建/编辑产品时,“域模型”才可能有用。这是正确的吗?
      • 是的,当数据进入您的应用程序并强制执行不变量时,富域模型对您的写入(创建/编辑)具有更多价值。使用域模型进行读取(显示列表/详细信息)是矫枉过正的,这通常会导致您的应用程序性能低下。
      • 因此,如果用户想从详细信息页面(使用读取模型填充)编辑某些域模型,应用程序服务将首先从数据库中获取域模型,然后将所有值从读取模型复制到域模型,验证它并插入它?甚至在添加关联的情况下:例如,在为产品添加标签的情况下,服务将首先获取产品域模型,将标签添加到其子列表中,然后对其进行验证,然后对其进行编辑?
      • 是的。因此,如果用户想从详细信息页面编辑某些域模型:用户加载使用读取模型填充的页面,进行更改并发布更改,应用程序服务首先从数据库中获取域模型,使用发布的值更新聚合并保存它.但在此之后,您必须确保您的读取模型也已更新(最好是异步的)。以A better domain events pattern 为例,将域事件与 ORM 结合使用
      【解决方案3】:

      除了@tomliversidge 的回答,我建议您查看Composite UI 模式(您可以找到一个示例here)。

      您将有一个服务网关构建一个复合视图模型,其中包含来自 3 个服务(产品、制造商和类别)的信息。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2010-11-01
        • 2013-09-16
        • 1970-01-01
        • 2019-06-27
        • 1970-01-01
        相关资源
        最近更新 更多