JPA:父实体含两个子实体时,将子实体关联到单一父实体
解决方案
你可以通过以下几种方式解决这个JPA关联冗余的问题:
方法一:使用单向OneToOne关联
直接移除ShipmentAddress中的反向关联属性,仅在Shipment中维护正向的一对一关系。这种方式最简单,适合不需要从ShipmentAddress反向查询所属Shipment的场景。
修改后的ShipmentAddress类:
@Entity public class ShipmentAddress { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; @Column(nullable = false) private String street1; private String street2; // 移除所有指向Shipment的属性,仅保留地址相关字段 }
Shipment类保持原有代码不变,所有关联操作从Shipment端发起即可。
方法二:通过继承+鉴别器区分地址类型
将ShipmentAddress抽象为父类,创建两个子类分别对应发货地址和收货地址,父类中仅保留一个指向Shipment的关联属性,子类通过鉴别器字段区分类型。
- 抽象父类
ShipmentAddress:
@Entity @Inheritance(strategy = InheritanceType.SINGLE_TABLE) @DiscriminatorColumn(name = "address_type", discriminatorType = DiscriminatorType.STRING) public abstract class ShipmentAddress { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; @Column(nullable = false) private String street1; private String street2; @OneToOne private Shipment shipment; }
- 发货地址子类
FromAddress:
@Entity @DiscriminatorValue("FROM") public class FromAddress extends ShipmentAddress { // 无需额外字段,继承父类所有属性 }
- 收货地址子类
ToAddress:
@Entity @DiscriminatorValue("TO") public class ToAddress extends ShipmentAddress { // 无需额外字段,继承父类所有属性 }
- 修改
Shipment类关联子类:
@Entity @Table(name = "shipment") public class Shipment { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; @ManyToOne private AppUser user; @OneToOne(cascade = CascadeType.ALL, mappedBy = "shipment") private FromAddress fromAddress; @OneToOne(cascade = CascadeType.ALL, mappedBy = "shipment") private ToAddress toAddress; }
方法三:添加地址类型标记+过滤关联
在ShipmentAddress中添加一个枚举字段标记地址类型(发货/收货),使用@Where注解在Shipment中过滤出对应类型的地址,同时仅保留一个指向Shipment的关联属性。
- 定义地址类型枚举:
public enum AddressType { FROM, TO }
- 修改
ShipmentAddress类:
@Entity public class ShipmentAddress { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; @Column(nullable = false) private String street1; private String street2; @Column(nullable = false) @Enumerated(EnumType.STRING) private AddressType type; @ManyToOne private Shipment shipment; }
- 修改
Shipment类添加过滤条件:
@Entity @Table(name = "shipment") public class Shipment { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; @ManyToOne private AppUser user; @OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY) @JoinColumn(name = "from_address_id") @Where(clause = "type = 'FROM'") private ShipmentAddress fromAddress; @OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY) @JoinColumn(name = "to_address_id") @Where(clause = "type = 'TO'") private ShipmentAddress toAddress; }
内容的提问来源于stack exchange,提问作者Johnny boy
相关产品推荐
相关产品推荐

