2. JPA对象关系映射–值对象映射

在领域驱动设计中,有一些结构主表和明细表必须一起显现才能表达业务意义,明细表不能单独使用被称为值对象,主表表达业务对象称为实体,也称为聚合根。

1. 在实体中的值对象上增加 @OneToMany 注解

@Data
@Entity
public class SaleOrder {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer orderId;
    /**
     * 订单号
     */
    private String orderCode;
    /**
     * 交易金额
     */
    private BigDecimal tradeAmount;
    /**
     * 销售时间
     */
    private Date saleTime;
    /**
     * 订单状态
     */
    private String orderState;
    /**
     * 订单明细
     */
    @OneToMany
    private List<OrderDetail> orderDetailList;
}


@Entity
@Data
public class OrderDetail {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer orderDetailId;
    /**
     * 产品编码
     */
    private String productCode;
    /**
     * 数量
     */
    private Integer quantity;
    /**
     * 售价
     */
    private BigDecimal salePrice;
    /**
     * 折扣
     */
    private BigDecimal discount;
}

*运行后从数据库上看,形成3个表

  • sale_order 主表
  • order_detail 明细表
  • sale_order_order_detail_list 关系表

2. 增加 @JoinColumn 注解,去掉关系表

@OneToMany
@JoinColumn
private List<OrderDetail> orderDetailList;

明细表结构:

Table: order_detail

Columns:

order_detail_id int(11) AI PK

discount decimal(19,2)

product_code varchar(255)

quantity int(11)

sale_price decimal(19,2)

order_detail_list_order_id int(11)

从结构上讲自动增加了一个 order_detail_list_order_id int(11) 字段,并做了外键关联

3. 使用非主键做关联

在特殊场景下,不用主键id做,使用更有意义的order_code

@OneToMany
@JoinColumn(name = "orderCode", referencedColumnName = "orderCode")
private List<OrderDetail> orderDetailList;

name 为子表的关联属性

referencedColumnName 为主表的关联属性

注意: 使用此注解后,两个表没有自动建立外键依赖,且主表的order_code字段为建唯一索引

4. 执行写入操作时报错

问题1: fun.barryhome.jpa.domain.SaleOrder cannot be cast to java.io.Serializable

原因:Hibernate有二级缓存缓存会将对象写进硬盘,就必须序列化。

解决方法

public class SaleOrder implements Serializable {
    ...
}

问题2: object references an unsaved transient instance – save the transient instance before flushing: fun.barryhome.jpa.domain.OrderDetail

原因:当子对象不存在时,保存主对象时,必须级联保存子对象

解决方法:

@OneToMany(cascade = {CascadeType.MERGE, CascadeType.PERSIST})
@JoinColumn(name = "saleOrderCode", referencedColumnName = "orderCode")
private List<OrderDetail> orderDetailList;

5. 相关代码

@Data
@Entity
@Builder
public class SaleOrder implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer orderId;
    /**
     * 订单号
     */
    private String orderCode;
    /**
     * 交易金额
     */
    private BigDecimal tradeAmount;
    /**
     * 销售时间
     */
    private Date saleTime;
    /**
     * 订单状态
     */
    private String orderState;
    /**
     * 订单明细
     */
    @OneToMany(cascade = {CascadeType.MERGE, CascadeType.PERSIST})
    @JoinColumn(name = "saleOrderCode", referencedColumnName = "orderCode")
    private List<OrderDetail> orderDetailList;
}

@Entity
@Data
@Builder
public class OrderDetail {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer orderDetailId;
    /**
     * 产品编码
     */
    private String productCode;
    /**
     * 数量
     */
    private Integer quantity;
    /**
     * 售价
     */
    private BigDecimal salePrice;
    /**
     * 折扣
     */
    private BigDecimal discount;
}

2. JPA对象关系映射--值对象映射

原文 

https://segmentfault.com/a/1190000021976159

本站部分文章源于互联网,本着传播知识、有益学习和研究的目的进行的转载,为网友免费提供。如有著作权人或出版方提出异议,本站将立即删除。如果您对文章转载有任何疑问请告之我们,以便我们及时纠正。

PS:推荐一个微信公众号: askHarries 或者qq群:474807195,里面会分享一些资深架构师录制的视频录像:有Spring,MyBatis,Netty源码分析,高并发、高性能、分布式、微服务架构的原理,JVM性能优化这些成为架构师必备的知识体系。还能领取免费的学习资源,目前受益良多

转载请注明原文出处:Harries Blog™ » 2. JPA对象关系映射–值对象映射

赞 (0)
分享到:更多 ()

评论 0

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址