首页 > 解决方案 > 领域驱动设计 - 从 UI 增量保存

问题描述

我是 DDD 的新手,正在阅读有关它的文献,但在应用某些概念时遇到了麻烦。我正在展示我正在构建的应用程序的简化视图。这是一个房屋贷款申请系统。UI 有类似向导的步骤来收集信息,比如第 1 步是收集申请人信息,第 2 步是收集财产信息,第 3 步是捕获批准或拒绝的决定。在第 1 步中,每个应用程序都被分配了一个唯一的 ID。我的挑战是如何对每个步骤的增量保存进行建模。贷款申请是我的总根。根据我的阅读,每个根只有一个存储库,并且必须将整个根保存在一起以使其有效。但是 UI 会增量收集信息,并且在每一步中,应用程序实体都是有效的 - 当我保存第 1 步中的数据时,我的贷款申请对象是有效的。保存步骤 2 中的数据后,贷款申请对象仍然有效。在此处寻找有关如何设计 Api 和存储库的建议?如果 agg root 在每一步都有效并且可以小步保存,那么暴露一个保存 api 的意义何在?是否应该有 3 个单独的 Api 暴露给 UI,并且这 3 个 api 调用 3 个单独的 repo 类或 1 个 api 在一个 repo 上调用 3 个单独的方法?我正在使用实体框架保存到数据库。谢谢你。

标签: domain-driven-design

解决方案


应用程序的要求以及您对其建模的方式将影响您的操作方式。

(注意:我将使用 AR 作为聚合根)

在您的情况下,如果您有LoanApplication AR,它需要包含有关申请人财产的信息。

假设每个申请人都有一个独特的帐户,因此您可以跟踪申请人有多少贷款。

在这种情况下,申请人将是一个实体,并且可能是一个AR。它将拥有自己的存储库:ApplicantRepository。在这种情况下,需要从您的LoanApplication AR中引用申请人AR 。

这意味着在您的向导的第一步中,您可以使用申请人存储库搜索申请人创建一个新的申请人。如果要创建一个新的,您可以在第一步中创建并保存它。稍后您可以从LoanApplication引用申请人(通过引用或 ID)

如果你不想这样,那么申请人可以是一个值对象,它的信息将存储在LoadApplication AR中。

同样的事情也适用于Property:您可以拥有一个带有PropertyRepository的Property Entity,或者只是将PropertyInfo值对象存储到LoadApplication AR

另一个重要的事情是LoanApplication有一个生命周期。根据它的当前状态,它的不变量可能会改变。拥有一个经历不同阶段的AR是可以的。以在线商店为例。当您从亚马逊订购商品时,您的订单可以是 Approved 或 Pending(或其他状态),这是它的生命周期的一部分。当您想完成订单时,系统可能会在提交之前要求您提供付款详细信息。

在您的 ca 中,您可以通过设置状态为LoadApplication创建生命周期PendingSubmittedForApprovalApprovedRejected等。它可能还需要有关它为何被拒绝等的其他信息。

如果您想保存有关创建LoadApplication的过程的信息,您可以分配一个表示您LoadApplication仍在创建过程中的状态:PendingInProgress。这样,如果您的应用程序在中间崩溃,它可以通过获取LoadApplication并检查其状态来恢复。

您可以在LoadApplication AR中添加与其状态相关的行为(例如,如果它不处于SubmittedForApproval状态,它将不允许转换到Approved状态,并且如果它不处于InProgress状态,则不允许更改该属性(您不想更改状态为 Approved 或 SubmittedForApproval 时的财产申请人)。

实施保存:

如果您决定LoadApplication Aggregate将包含三个实体:LoadApplication、 Apply和Property,那么所有这些实体将一起保存和加载,因为该聚合是一个Transactional Boundary。该指南可以帮助实现 Save,但它可能很棘手。

这将取决于几个因素:

  • 你是什​​么数据库(SQL,MongoDB)?

  • 您是使用框架(NHibernate、Mongoose)还是使用原生 API(使用原始 SQL)?

由于只有LoadApplicationRepository将使用申请人属性保存LoadApplication ,因此即使申请人再次保存到数据库也没有问题,因为不会对其进行任何更改。您只会用相同的数据覆盖现有数据,这对性能来说不是很酷,但这不是您的逻辑问题。

另一方面,如果您使用 ORM,它们可以检测对象中的更改并仅生成所需的查询以仅更新对数据库的新更改。在这种情况下,如果您说向LoadApplication添加一个属性,如果将选择它并仅更新数据库中的属性

例如,假设您正在使用带有 (N)Hibernate 或 EntityFramewok 的 SQL 数据库,您的 ORM 将跟踪添加属性的更改并生成 SQL 以将其插入数据库中的属性表,但不会为已经生成的更新插入现有的申请人,因为它没有改变。

如果您正在使用例如原始 SQL 编写自己的逻辑,那么您将必须自己编写跟踪更改的逻辑。

一种方法是在LoanApplicaton AR中添加更改集合,该集合将包含更改/事件(ApplicantAssigned、PropertyAssigned、SomethingChanged 等),以便您可以在 Save 方法中使用它们来根据更改生成 SQL。当您保存聚合时,您可以清除更改。

这是一篇关于建模聚合的精彩文章:http: //dddcommunity.org/library/vernon_2011/

以下是关于域事件的夫妇: https ://www.martinfowler.com/eaaDev/DomainEvent.html https://lostechies.com/jimmybogard/2014/05/13/a-better-domain-events-pattern/


推荐阅读