【问题标题】:How to handle Persistence with Rich Domain Model如何使用富域模型处理持久性
【发布时间】:2017-07-06 07:28:44
【问题描述】:

我正在重新设计我的 NodeJS 应用程序,因为我想使用富域模型概念。目前我正在使用贫血域模型,但扩展性不好,我到处都能看到“ifs”。

我已经阅读了一堆博客文章和 DDD 相关的博客,但有些东西我根本无法理解……我们如何正确处理 Persistence。

首先,我想描述一下我定义的层及其用途:

持久性模型

  • 定义表模型。定义表名、列、键和关系
  • 我将 Sequelize 用作 ORM,因此使用 Sequelize 定义的模型被视为我的持久性模型

领域模型

  • 实体和行为。与作为业务领域的一部分创建的抽象相对应的对象
  • 我创建了几个类,这里​​最好的一点是我可以从层次结构中受益来解决所有问题(没有大量的 ifs yay)。

数据访问对象 (DAO)

  • 负责数据管理以及将持久性模型的条目转换为域模型的实体。所有持久性相关的活动都属于这一层
  • 在我的例子中,DAO 工作在基于持久性模型创建的 Sequelize 模型之上,但是,我正在根据属性对不同对象中的数据库交互返回的记录进行序列化。例如:如果我有一个表,其中包含一个名为“UserType”的列,其中包含两个值 [ADMIN,USER],当我在此表上选择条目时,我将根据用户类型序列化返回,因此具有类型的用户: ADMIN 将是 AdminUser 类的一个实例,其中类型为: USER 的用户将只是一个 DefaultUser...

服务层

  • 负责所有通用业务逻辑,例如不属于任何域对象行为的实用程序和其他服务

客户层

  • 任何使用对象并负责触发持久性的消费者类

现在,当我实现客户端层时,混乱就开始了……

假设我正在实现一个新的 REST API:

POST: .../api/CreateOrderForUser/
{
  items: [{
    productId: 1,
    quantity: 4
  },{
    productId: 3,
    quantity: 2
  }]
}

在我的处理程序函数上,我会有类似的东西:

function(oReq){
  var oRequestBody = oReq.body;
  var oCurrentUser = oReq.user; //This is already a Domain Object
  var aOrderItems = oRequestBody.map(function(mOrderData){
    return new OrderItem(mOrderData); //Constructor sets the properties internally
  });
  var oOrder = new Order({
    items: aOrderItems
  });

  oCurrentUser.addOrder(oOrder);

  // So far so good... But how do I persist whatever 
  // happened above? Should I call each DAO for each entity 
  // created? Like, first create the Order, then create the 
  // Items, then update the User?

}

我发现使其工作的一种方法是合并持久性模型和域模型,这意味着oCurrentUser.addOrder(...) 将执行所需的业务逻辑,并最终调用 OrderDAO 以将订单与项目一起持久化.不好的是现在addOrder 也必须处理事务,因为我不想添加没有项目的订单,或者更新没有订单的用户。

那么,我在这里缺少什么?

【问题讨论】:

  • 如果您想了解完整的 DDD,您可能需要阅读有关存储库、聚合、聚合根和应用程序服务的更多信息。还要看看工作单元的概念。如果您需要应用服务通常如何实现的具体示例,恐怕您必须深入研究非节点代码示例。

标签: node.js architecture domain-driven-design sequelize.js rich-domain-model


【解决方案1】:

聚合。

这是故事中缺失的部分。

在您的示例中,订单项可能没有单独的表(并且没有关系,没有外键......)。这里的项目似乎是 values(描述一个实体,即:“45 美元”),而不是 entities(随时间变化且我们跟踪的事物,即:银行帐户)。因此,您不会直接保留 OrderItems,而是仅保留 Order(其中包含项目)。

我希望找到的代替您的评论的代码可能类似于orderRepository.save(oOrder);。此外,我希望用户是订单中的弱引用(仅通过 id),而不是像您的 oCurrentUser.addOrder(oOrder); 代码所建议的那样包含在用户中的订单。

此外,您描述的层是有道理的,但在您的示例中,您将交付问题(请求、响应等概念)与域概念(将项目添加到新订单)混合在一起,我建议您看看在已建立的模式中保持这些关注点解耦,例如 六边形架构。这对于单元测试 尤其重要,因为您的“客户端代码”可能是测试而不是处理函数。检索/创建 - 做某事 - 保存代码通常是描述您的用例的应用程序服务中的一个函数。

Vaughn Vernon 的“实施领域驱动设计”是一本关于 DDD 的好书,肯定会更深入地阐明这个主题。

【讨论】:

    猜你喜欢
    • 2015-01-31
    • 2022-01-15
    • 2012-12-11
    • 1970-01-01
    • 1970-01-01
    • 2015-02-19
    • 2017-03-27
    • 2018-08-30
    • 1970-01-01
    相关资源
    最近更新 更多