原创 | 使用JPA实现DDD持久化-O/R阻抗失配(2/2)

本文探讨了使用JPA在领域驱动设计中处理关联问题,包括关联的方向性和多对多关联的映射。讨论了数据导航在性能上的挑战以及值对象的生命周期管理。在关系模型中,JPA如何处理值对象的持久化和删除,以及与实体生命周期的关联。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在这里插入图片描述
在这里插入图片描述

4. 关联问题

在领域模型中,关联表示了实体之间的关系。面向对象的语言如Java使用对象引用来表示关联,而在关系模型中,外键约束列表示了一个关联,它带有一些键值的副本。

4.1 关联的方向性

关联是有方向性的,通过对象引用的方式从一个实体(或值对象)指向另一个实体。它们都是指针。

在这里插入图片描述

Java代码中,体现为一个实体类拥有一个类型为另一个实体类(或其集合)的属性:

public class Account {
  private Customer owner;
  ...
}
public class Customer {
  ...
}

如果要实现双向关联,需要在两端分别定义关联:

在这里插入图片描述

关系模型采用外键的方式记录表之间的关联关系。在特定的方向上导航对于关系模型来说没有意义,因为可以使用join和投影操作创建任意的数据关联。其挑战在于将一个完全开放、独立于数据使用应用程序的数据模型影射到一个依赖应用程序的导航模型——这个特定应用程序所需的关联约束视图。

4.2 多对多关联

在领域模型中常常存在多对多关联。例如在选课系统中,一个学生可以选择多门课程,一门课程也可以被多个学生选中。

在这里插入图片描述

而关系模型中,只能通过外键表示“多对一”或者"一对多"关联,没有对“多对多”关联的直接支持。

5. 数据导航问题

Java中,可以跟随关联的方向遍历对象网络,例如:

aUser.getBillingDetails().iterator().next();

但是这样的访问会导致著名的n + 1问题:需要为每一个访问节点或者对象网络的集合执行一条语句,导致性能低下。

在数据库中,可以根据外键关联用join的方式一次性获取数据,因而可以大大提高性能:

select * from USERS u
   left outer join BILLING_DETAILS bd on bd.USER_ID = u.ID
   where u.ID = 123;

6. 值对象的生命周期问题

前文说过,实体的状态分为“值”和“关联”两种,值包括简单值(数字、字符串、布尔值、日期等等)和值对象(EmailMoneyAddress等等)。值位于实体的边界之内,是实体的内在组成部分,而关联指向一个外部实体,不是实体的内在组成部分。因此,作为实体属性的简单值和值对象,不论是单值的还是多值的(数组、列表或集合等形式),都是实体的固有组成部分,从属于实体,不具备独立的生命周期。它们会随着实体创建而创建,随着实体的更新而更新,也会随着实体的删除而删除。不需要任何额外的步骤去处理值的生命周期。

举个例子,在电商软件中有三个领域类,包括一个实体类Customer和两个值对象AddressCustomerNameCustomer类拥有一个类型为PersonName的单值属性name以及一个类型为Address的多值属性shippingAddresses(一个顾客拥有一个名称和多个送货地址)。下面是Java代码:

public class Customer {
  private long id;
  private CustomerName name;
  private Set<Address> shippingAddresses = new HashSet();
  ...
  //getters and setters
}

public class CustomerName {
  private String firstName;
  private String lastName;
  ...
  //getters and setters

}

public class Address {
  private String postalCode;
  private String province;
  private String city;
  private String street;
  ...
  //getters and setters
}

根据领域模型的含义,值对象PersonNameAddress都不需要单独持久化,体现在:

  • 当保存新建的Customer实体对象时,单值属性name持有的值对象CustomerName和多值属性shippingAddresses指向的值对象Address的集合都会自动保存,而不需要分别保存CustomerCustomerNameAddress
  • 当对shippingAddresses这个集合增减条目或修改其中部分地址信息时,只须用新的地址集合整体替换掉现有的地址集合,不用担心其中哪些是新的,哪些是旧的;既不必担心造成重复,也不必担心出现“孤儿对象”——在这里指不关联到任何PersonAddress实例。
  • 当删除Person实体对象时,它持有的CustomerName实例和Address集合会一并删除。

而关系模型没有实体和值对象之别。它只认知两个表之间通过外键存在的关联关系。必须分别管理关联的两端的表,而不能做到级联持久化或者级联删除。

详细内容请戳这里↓↓↓

原创 | 使用JPA实现DDD持久化-O/R阻抗失配(2/2)

这一节就讲到这里,下一节我们讲"JPA,Hibernate与Spring Data JPA"。

如果觉得有收获,点个【赞】鼓励一下呗!

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值