解密DDD:高内聚对象组的维护之道( 三 )


文章插图
其中:

  1. address_id 存储的是 Address 实体的主键;
  2. pay_id 存储的事 Pay 实体的主键;
    其中,插入数据的sql如下:
    Hibernate: insert into address (detail) values (?)
    Hibernate: insert into pay_info (order_id, price) values (?, ?)
    Hibernate: insert into order_info (address_id, pay_id, status, total_price, total_selling_price, user_id) values (?, ?, ?, ?, ?, ?)
可见,执行时先插入 address 和 pay 获取主键后,在插入到 order_info 表,从而维护外键的有效性 。
3.1.2. 单向一对多实体定义如下:
// 聚合根实体@Entity@Table(name = "order_info")public class Order{@Id@GeneratedValue(strategy = GenerationType.IDENTITY)private Long id;// 添加 @OneToMany 注解@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)// 指定多端的关联列(如果不指定,会使用第三张表来保存关系@JoinColumn(name = "order_id")private List<OrderItem> orderItems = new ArrayList<>();// 忽略其他属性}// OrderItem 实现@Entity@Table(name = "order_item")public class OrderItem {@Id@GeneratedValue(strategy = GenerationType.IDENTITY)private Long id;// 忽略其他属性}插入记录后,表数据如下:
order 表数据:
解密DDD:高内聚对象组的维护之道

文章插图
order+item表数据:
解密DDD:高内聚对象组的维护之道

文章插图
其中 order_item 表中的 order_id 指向 order_info 表的主键 。
3.2. 继承关系继承是面向对象编程的核心特性,但这一特性确与数据库的关系模型产生巨大阻抗 。
JPA 中提供了三种继承模型,包括:
  1. 单表继承策略(SINGLE_TABLE) 。父类实体和子类实体共用一张数据库表,在表中通过一列辨别字段来区别不同类别的实体;
  2. Joined 策略(JOINED) 。父类和子类分别对应一张表,父类对应的表中只有父类自己的字段,子类对应的表中中有自己的字段和父类的主键字段,两者间通过 Join 方式来处理关联;
  3. 每个实体一个表策略(TABLE_PER_CLASS) 。每个实体对应一个表,会生成多张表,父类对应的表只有自己的字段 。子类对应的表中除了有自己特有的字段外,也有父类所有的字段 。
为了更好的对比各种策略,我们以一个业务场景为案例进行分析 。
在优惠计算过程中,需要根据不同的配置策略对当前用户进行验证,以判断用户是否能够享受优惠,常见的验证策略有:
  1. 只有特定用户才能享受 。
  2. 只有男士或女士才能享受 。
  3. 只有VIP特定等级才能享受 。
  4. 未来还有很多
为了保障系统有良好的扩展性,引入策略模式,整体设计如下:
解密DDD:高内聚对象组的维护之道

文章插图
那接下来便是将这些实现类存储到数据库,然后在方便的查询出来 。
3.2.1. 单表继承
单表继承非常简单,也最为实用,数据库表只有一张,通过一列辨别字段来区别不同类别的实体 。
它的使用涉及几个关键注解:
  1. @Inheritance(strategy = InheritanceType.SINGLE_TABLE),添加在父类实体,用于说明当前使用的是 单表策略;
  2. @DiscriminatorColumn(name="区分类型存放的列名"),添加在父类实体,用于说明使用哪个列来区分具体类型;
  3. @DiscriminatorValue(value = https://www.isolves.com/it/cxkf/bk/2023-09-11/"当前类型的标识") 添加到子类实体上,用于说明当前子类的具体类型;
相关实体代码如下:
// 父类@Entity// 单表表名@Table(name = "activity_matcher")// 当前策略为单表策略@Inheritance(strategy = InheritanceType.SINGLE_TABLE)// activity_type 列用于存储对应的类型@DiscriminatorColumn(name = "activity_type")@Datapublic abstract class BaseActivityMatcher implements ActivityMatcher {@Id@GeneratedValue(strategy = GenerationType.IDENTITY)private Long id;private ActivityMatcherStatus status = ActivityMatcherStatus.ENABLE;}// SpecifyUserMatcher 实现类@Entity// 使用 SpecifyUser 作为标记@DiscriminatorValue("SpecifyUser")public class SpecifyUserMatcherextends BaseActivityMatcherimplements ActivityMatcher {// 省略属性和方法}// SexMatcher 实现类@Entity// 使用 Sex 作为标记@DiscriminatorValue("Sex")public class SexMatcherextends BaseActivityMatcherimplements ActivityMatcher {// 省略属性和方法}@Entity// 使用 VipLevel 作为标记@DiscriminatorValue("VipLevel")public class VipLevelMatcherextends BaseActivityMatcherimplements ActivityMatcher {// 省略属性和方法}


推荐阅读