知识卡片

值对象简化数据库设计:从"数据建模为中心"转向"领域建模为中心"

普通读书笔记卡

内容

传统数据建模按数据库范式设计,每个实体对应一张表,每个属性对应一列,一个主表往往关联出N个从表。DDD引入值对象,是希望把设计重心从”数据建模为中心”转向”领域建模为中心”:面对”人员+地址”这类场景,如果把地址也做成独立实体、单独建表,会增加不必要的实体和表、带来表间关系的复杂度;但如果把地址所有属性直接摊平塞进人员表,又会破坏地址作为一个独立业务概念的完整性。值对象给出的折中方案是:在领域建模层面把地址设计成值对象(保留业务概念的完整性),但在数据建模层面只建人员这一张表,把地址的属性值嵌入进去(不增加数据库复杂度),这个过程中会有一次从DO到PO的转换。具体嵌入方式有两种:属性嵌入(值对象的每个字段拆开变成实体表里的普通列)适合单一属性或单条记录的值对象;序列化大对象(把值对象整体序列化成JSON字符串存进一个字段)适合更复杂的值对象。这个案例给出一条通用的建模启示:业务概念上是否该拆成独立对象,与数据库物理层面是否该拆成独立表,是两个可以分开决策的问题,不必因为要保持业务概念清晰就被迫接受数据库层面的复杂化,反过来也不必因为想简化数据库就牺牲业务概念的完整性。

参考来源

- 位置:第7章《实体和值对象:领域模型的基础单元》"7.2 值对象","3. 值对象的数据库形态"(源文件:_epub-src/OEBPS/Text/chapter3-3-2.xhtml) - 结论依据:原文说明"DDD引入值对象是希望实现从'数据建模为中心'向'领域建模为中心'的转变,减少数据库表的数量和表与表之间复杂的依赖关系……我们可以把地址作为值对象,把人员作为实体,这样就可以保留地址的业务含义和概念完整性。而在数据建模时,我们可以只创建人员持久化对象和人员数据库表,将地址的属性值嵌入人员实体数据库表中",直接支撑本卡片结论。 - 原始内容:DDD引入值对象是希望实现从"数据建模为中心"向"领域建模为中心"的转变,减少数据库表的数量和表与表之间复杂的依赖关系,尽可能简化数据库设计,提升数据库性能。