JPA关联类自动获取Product生成ID的实现方案咨询
问题:保存Product实体时自动为关联实体赋值productId
现有如下Product实体类,其id通过@GeneratedValue实现数据库自动递增:
@Data @Entity @Table(name = "products", schema = "laboratory", catalog = "laboratory") @JsonIgnoreProperties({ "hibernateLazyInitializer", "handler" }) public class Product { @Id @GeneratedValue private int id; @ManyToOne(fetch = FetchType.LAZY, cascade= CascadeType.ALL) @JoinColumn(name = "project_id") @Transient private Project project; // 只读字段 @Column(name="project_id") // 存储关联项目的id到数据库 private int projectId; @OneToOne(cascade = CascadeType.ALL) @JoinColumn(name="id") private Inspection inspection; @OneToOne(cascade = CascadeType.ALL) @JoinColumn(name="id") private Information information; @OneToOne(cascade = CascadeType.ALL) @JoinColumn(name="id") private Departure departure; private String un; private String tc; }
Product需要关联Inspection、Information、Departure三个实体,以Information为例,其结构如下:
@Data @Entity @Table(name = "products_informations", schema = "laboratory", catalog = "laboratory") @JsonIgnoreProperties({ "hibernateLazyInitializer", "handler" }) public class Information { @Id private int productId; private String description; private String model; private int year; private String serialNumber; private int odometre; private int noCrochet; private int nbKeys; private String localisation; private String cemeteryPosition; @JsonFormat(pattern = "yyyy-MM-dd") private Date receptionDate; }
需求:调用save()方法保存Product时,三个关联实体的productId能自动获取Product生成的id,无需在控制器手动赋值。
解决方案
1. 修正关联映射逻辑
原代码中Product类的@OneToOne注解配置错误,@JoinColumn(name="id")会导致关联实体使用自身的id字段关联,不符合需求。需要通过双向关联+@MapsId注解实现主键自动同步。
2. 修改Product类的关联注解
将Product中三个@OneToOne关联改为mappedBy形式,指向关联实体中关联Product的属性名:
@Data @Entity @Table(name = "products", schema = "laboratory", catalog = "laboratory") @JsonIgnoreProperties({ "hibernateLazyInitializer", "handler" }) public class Product { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) // 明确指定自增策略,避免依赖默认配置 private int id; @ManyToOne(fetch = FetchType.LAZY, cascade= CascadeType.ALL) @JoinColumn(name = "project_id") @Transient private Project project; @Column(name="project_id") private int projectId; // 改为mappedBy,指向关联实体中的product属性 @OneToOne(mappedBy = "product", cascade = CascadeType.ALL, fetch = FetchType.LAZY) private Inspection inspection; @OneToOne(mappedBy = "product", cascade = CascadeType.ALL, fetch = FetchType.LAZY) private Information information; @OneToOne(mappedBy = "product", cascade = CascadeType.ALL, fetch = FetchType.LAZY) private Departure departure; private String un; private String tc; }
3. 修改关联实体(以Information为例)
给关联实体的@Id字段添加@MapsId注解,并添加双向关联的Product属性:
@Data @Entity @Table(name = "products_informations", schema = "laboratory", catalog = "laboratory") @JsonIgnoreProperties({ "hibernateLazyInitializer", "handler" }) public class Information { @Id @MapsId // 该注解会让Hibernate将关联Product的id赋值给当前实体的主键productId private int productId; // 双向关联Product,指定外键为product_id(即当前实体的主键) @OneToOne(fetch = FetchType.LAZY) @JoinColumn(name = "product_id") private Product product; private String description; private String model; private int year; private String serialNumber; private int odometre; private int noCrochet; private int nbKeys; private String localisation; private String cemeteryPosition; @JsonFormat(pattern = "yyyy-MM-dd") private Date receptionDate; }
Inspection和Departure类做完全相同的修改即可。
4. 保存逻辑示例
保存时只需构建Product及关联实体的关系,无需手动赋值productId:
// 构建关联实体 Information info = new Information(); info.setDescription("测试描述"); // 其他属性赋值... // 构建Product并关联 Product product = new Product(); product.setInformation(info); info.setProduct(product); // 建立双向关联 // 保存Product,Hibernate会自动处理id同步 productRepository.save(product);
原理说明
@MapsId注解会让Hibernate将关联实体(Product)的主键值,赋值给当前实体的主键(productId)。CascadeType.ALL配置会让save()操作级联到关联实体,Hibernate会先保存Product生成自增id,再自动将该id赋值给关联实体的productId,最后保存关联实体。
内容的提问来源于stack exchange,提问作者Charlo Poitras
相关产品推荐
相关产品推荐

