V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
lihongjie0209
V2EX  ›  Java

DDD 中的 聚合根(Aggregate Root)在半自动化的 ORM 中如何持久化?

  •  
  •   lihongjie0209 · 2019-04-16 10:36:02 +08:00 · 4813 次点击
    这是一个创建于 2084 天前的主题,其中的信息可能已经有所发展或是发生改变。

    我是用的是一个类似 Mybatis 的 ORM,很显然它不支持透明的持久化。聚合根在每次更新之后如何在 Repository 中识别到这些更新并持久化到数据库中。

    在《实现领域驱动设计》中作者提到的两种方式

    1. 使用 ORM 如 Hibernate
    2. 使用 document store 如 MogoDB

    我现在的问题是:

    1. 是不是这种半自动化 ORM+关系型数据( MYSQL )无法实现 DDD

    2. 或者实现的代价比较大(如在聚合根内部保存所有的操作记录,然后再 Repository 中根据这些记录持久化)

    3. 或者是必须使用 Event Source 这种方法来持久化(对于我来说太重了)

    11 条回复    2019-04-19 10:12:54 +08:00
    ChoateYao
        1
    ChoateYao  
       2019-04-16 10:48:12 +08:00
    1. 可以实现
    2. 这是一种思路
    3. Event Source 并不是这么用的

    第二种思路切分出来,使用 Domain Service 手动解决。

    要不然你自己完善基础设施层,让 Repository 支持。
    gsj987
        2
    gsj987  
       2019-04-16 10:51:43 +08:00
    一般使用 UnitOfWork 模式 来感知 Repository 的变化,或简单的把显式的操作放在 Application 层
    lihongjie0209
        3
    lihongjie0209  
    OP
       2019-04-16 11:04:32 +08:00
    @ChoateYao
    Domain Server 不应该关心持久化的问题吧
    一般都是直接调用
    repo.update(ar);

    我的问题是 repo.update 如何实现?
    lihongjie0209
        4
    lihongjie0209  
    OP
       2019-04-16 11:05:52 +08:00
    @gsj987

    Application 更不应该关心持久化的问题

    repo.update(ar);

    应该是 repo 唯一暴露的更新接口,不存在显式操作
    ChoateYao
        5
    ChoateYao  
       2019-04-16 11:13:14 +08:00
    @lihongjie0209 实际情况就是基础设施层没做好的,作出的妥协。

    因为你不可能在 Application Layer 做数据拼装然后持久化,落地一个理念根据目前的情况不断做调整以达到最优情况。
    gsj987
        7
    gsj987  
       2019-04-16 11:25:44 +08:00
    @lihongjie0209 我指的是在 application 层对 repository 的显式调用,比如你说的 update。在实践中,repository 会用 IRepository 的形式作为基础设施服务,这样 application 就和具体的 orm 解除关联了。当然一般情况下,都会使用基础框架的 UoW 完成隐式更新。
    lihongjie0209
        8
    lihongjie0209  
    OP
       2019-04-16 11:40:27 +08:00
    @gsj987

    类似于 Mybatis 这种半自动的 ORM, 如何实现 UOW 中的隐式更新?
    gsj987
        9
    gsj987  
       2019-04-16 13:50:28 +08:00
    @lihongjie0209 这里篇文章讲了具体的实现 https://github.com/sheng-jie/UnitOfWork

    因为 UoW 统一了持久化方法和事务,所以就可以用 AOP 的方式在框架层面对 UoW 进行隐式调用,如 ABP 的做法: http://www.cnblogs.com/1zhk/p/5309043.html

    UoW 的作用是追踪 entity 在多个仓库间变化的依赖关系,自动帮你解决事务方法,让事务和持久化在多个聚合中保持统一,但是 IRepsoitory 的方法调用还是需要的。如果你的意思就 tracking changes 然后不调用 IRepository 更新的话,这个可能需要 orm 本身的支持。
    lihongjie0209
        10
    lihongjie0209  
    OP
       2019-04-18 10:50:06 +08:00
    @gsj987
    感谢你的回复,我下去也看了 UOW, 发现一个问题

    UOW 的核心是对对象的状态标记, 如果 被修改, 被删除之类的。

    我找一个图, 可以帮忙说明一下吗?

    https://imgur.com/HePiXYq
    gsj987
        11
    gsj987  
       2019-04-19 10:12:54 +08:00
    @lihongjie0209 明白你的意思了。这个确实和 UoW 的概念没太大关系,UoW 主要作用就是事务。DDD 的设计战术之一就是一次操作只能修改一个 AR,所以需要 Domain Event 之类的东西来做关联,UoW 让各 AR 实现最终一致。

    你这个例子中,确实没法在 Domain 或者 Application 层做相关的操作,因为对 Domain 他不关心持久化,对 Application 他只能看到 AR,不知道里面具体的实现。

    这里你提问的半自动化 ORM,就是类似 Dapper 这样的吧?这些 micro-ORM 更多关注的是 M,而像 Hibernate 或者 EF 之类的更多的关注的是 O,也就是说前者还是一个面向数据库,效率高,透明轻快,而后者是面向对象,但是重量,不透明。在 DDD 中,领域对数据库无感知,甚至很多实践还强调聚合根里能用值对象就用值对象,所以无法在 Domain 中体现从对象关系变化映射到数据库变化的关联,这些都是由 Repository 完成的。

    那么在如 EF 中,这种关联是自动实现的,因为他有 changetracker,另一方面,他还自己实现了 UoW。而 micro-ORM 没有这些,那就只能手动来做。具体的可以在 Repository 的实现中,对 AR 下的各 entity 的修改进行检查、保存。代价就是每一个特殊的检查都需要手动实现(或者如你的思路 2,自己实现一个 changetracker,如 Dapper.Contrib 就有类似的实现)。另外有些思路中,会拿 ORM 和 micro-ORM 混用,取两者的优点于一身 https://msdn.microsoft.com/zh-cn/magazine/mt703432.aspx
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2760 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 27ms · UTC 09:24 · PVG 17:24 · LAX 01:24 · JFK 04:24
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.