【问题标题】:Should domain object be created by event handler in aggregate域对象是否应该由事件处理程序聚合创建
【发布时间】:2020-01-15 12:20:48
【问题描述】:

当我们在聚合上调用域操作时,我们传递一些原语/域对象,我们验证一些业务规则并在最后应用域事件。当我们最终应用事件时,我们会更新对象的状态。在这最后的步骤中,我们必须从存储库创建对象或加载对象。这对我来说似乎很困难或错误,因为有很多重复的任务。

这是一个例子:

域操作

def create(uuid:, name:, description:, start_date:, end_date:, customer:, contact_person: , type: , manager:,
           department:, author:)
  result = Contracts::CreateContract.new(object: self).call(start_date: start_date, end_date: end_date)
  raise Exceptions::DomainError.new(payload: result) if result.errors.present?
  data = build_creat_event_data(uuid: uuid,
                           name: name,
                           description: description,
                           start_date: start_date,
                           end_date: end_date,
                           customer: customer,
                           contact_person: contact_person,
                           type: type,
                           manager: manager,
                           department: department,
                           author: author)
  apply(ProjectManagementDomain::Events::ProjectCreated.strict(data: data))
end

申请活动

def apply_project_created(event)
      @uuid = event.data[:uuid]
      @name = event.data[:name]
      @description = event.data[:description]
      @status = STATUSES.dig(:draft)
      @type = ProjectType.new(event.data[:type])
      @start_date = event.data[:start_date]
      @end_date = event.data[:end_date]
      @customer = Customer.new(event.data[:customer])
      @manager = Manager.new(event.data[:manager])
      @department = Department.new(event.data[:department])
      @contact_person = ContactPerson.new(event.data[:contact_person])
      @legacy_id = event.data[:legacy_id]
    end

正如您在上面的代码中看到的,我必须构建 event_data build_creat_event_data,它将域对象转换为事件的原语(因为建议将原语放入事件中)。然后,当我必须应用该事件时,我必须再次创建对象。我做错了还是缺少了什么。

这里最好的方法应该是什么?

【问题讨论】:

    标签: ruby domain-driven-design cqrs event-sourcing rails-event-store


    【解决方案1】:

    我会从域中的一些想法开始重新考虑。 在def create 中创建的Contract 对我来说似乎是另一个聚合。 如果我要为该域定义一个域模型,我不会在这里创建它,我只会将 contract 作为参数传递给 create 方法。这将是ProjectManagementDomain::Contract 而不是Contracts::Contract(这表明合同是另一个子域的一部分)。顺便说一句,customercontract_persondepartment ......等等)。

    另一件事是,对我来说,这个方法和这个域事件处理了太多的数据。我希望有更精细的域事件和更具体的业务操作。在这里应用的好的启发式方法是只处理一起更改的数据。除非您使用 Jira 构建项目管理域(*用您讨厌的另一个工具替换 Jira)集成,否则这可以建模为一组操作并作为结果域事件发布。 IE。你能创建一个没有定义日期的项目吗?您可以创建一个没有分配客户/经理/部门/联系人的项目吗?

    建议将原语放入事件中

    是的。这是正确的。但是你仍然可以在这里传递域对象,尤其是值对象。对我来说唯一的限制是它们必须被序列化为原始类型,并且这里使用的对象必须在同一个有界上下文的范围内。此外,我永远不会在其他有界上下文(避免耦合)消耗的域事件中发布对象。

    这么快 TL;DR:

    • 重新考虑您的域模型
    • 保持聚合较小
    • 您的事件甚至更小(尤其是您用于聚合事件溯源的事件,您可以在有界上下文之外发送数据时使用摘要事件模式)

    【讨论】:

      猜你喜欢
      • 2015-01-08
      • 1970-01-01
      • 1970-01-01
      • 2021-07-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-08-15
      • 1970-01-01
      相关资源
      最近更新 更多