在域驱动设计中获取关联的聚合

时间:2016-08-06 06:51:10

标签: domain-driven-design

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

    Repeater
    {
        model: ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]
        CheckBox
        {
            function isChecked() {
                return ((days & (1 << index)) != 0);
            }

            text: modelData
            checked: isChecked()
            onClicked:
            {
                if (checked) {
                    days |= (1<<index);
                }
                else {
                    days &= ~(1<<index);
                }

                // now rebind the item's checked property
                checked = Qt.binding(isChecked);

            }
        }
    }

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

  1. 我的产品服务部门提出另一个请求获取的请求 CategoryId和ManufacturerId
  2. 或者我可以在从产品库中获取产品时获取它们。
  3. 但我不需要所有的属性,我只需要他们的头衔。我面临着与所有领域模型类似的问题。

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

3 个答案:

答案 0 :(得分:2)

有多种方法可以解决这个问题:

本地缓存/查看模型

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

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

对数据进行非规范化

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

举报“域名”

您可以拥有一个完全独立的服务,用于侦听来自其他服务的数据并维护UI的视图模型。这将使您的其他服务不了解其他服务的顾虑。使用事件驱动系统时,您将从其他服务中侦听事件,以便为UI构建视图模型

答案 1 :(得分:0)

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

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

答案 2 :(得分:0)

  

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

如我所见,“类别名称”和“制造商名称”用于显示,因此它与演示文稿有关。 我建议只为该屏幕提供单独的阅读模型(参见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

  • 如果我们的聚合是事件来源,那么您只需听取域事件(例如CategoryNameChanged / ManufacturerNameChanged),然后将它们投影(非规范化)到ProductReadModel并存储它在任何存储空间(甚至在内存中)。

  • 如果您的聚合在关系数据库中持久存在,您还可以触发和项目/非规范化域事件。