JPA持久化后嵌入式ID的自动生成字段idMaterialResource为null
问题分析与解决方案
核心问题
你遇到的两个关键问题:
- 数据库脚本的主键字段名与实体类映射不匹配,导致JPA无法正确识别主键
- 嵌入式复合主键中自动生成的ID字段,默认不会被JPA自动回填到实体对象中
步骤1:修正数据库脚本
你的Flyway脚本中主键字段名错误,与实体类的列名不对应,这会导致JPA映射异常。修正后的SQL如下:
CREATE TABLE IF NOT EXISTS material_resource( id_materialresource INT NOT NULL AUTO_INCREMENT, id_company INT NOT NULL, name VARCHAR(255) NOT NULL DEFAULT "", identifier VARCHAR(255) NOT NULL DEFAULT "", fromDate DATE NOT NULL, toDate DATE NOT NULL, -- 修正主键字段,与实体类列名保持一致 PRIMARY KEY (id_materialresource, id_company) );
步骤2:解决ID回填问题
针对嵌入式ID的IDENTITY生成字段,有三种可行方案:
方案A:手动刷新实体(快速解决)
在persist操作后,调用EntityManager的refresh方法,强制从数据库同步最新的实体状态,生成的ID会被回填:
MaterialResourceId id = new MaterialResourceId(null, 1); MaterialResource materialResource = new MaterialResource(id, "Material resource name", ...); EntityManager em = getEntityManager(); em.persist(materialResource); // 刷新实体获取生成的ID em.refresh(materialResource); // 此时materialResource.getMaterialResourceId().getIdMaterialResource()已赋值
方案B:调整JPA配置(优雅解决)
确保Hibernate启用新的生成器映射(Spring Boot默认已开启),并确认嵌入式ID的注解配置正确:
- 如果是Spring Boot,在
application.properties中添加(默认已开启,可省略):
spring.jpa.hibernate.id.new_generator_mappings=true
- 保持现有嵌入式ID结构,确保
@GeneratedValue和@Column注解配置正确:
@Embeddable @Data @AllArgsConstructor @NoArgsConstructor public class MaterialResourceId implements Serializable { private static final long serialVersionUID = 1L; @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "id_materialresource", nullable = false) private Integer idMaterialResource; @Column(name = "id_company", nullable = false) private Integer idCompany; }
方案C:改用@IdClass替代@EmbeddedId(可选)
如果觉得嵌入式ID配置繁琐,可以切换为@IdClass实现复合主键,这种方式下ID会自动回填:
- 主键类保持不变(无需
@Embeddable注解):
@Data @AllArgsConstructor @NoArgsConstructor public class MaterialResourceId implements Serializable { private static final long serialVersionUID = 1L; private Integer idMaterialResource; private Integer idCompany; }
- 修改实体类:
@Entity @Table(name = "material_resource") @Getter @Setter @AllArgsConstructor @NoArgsConstructor @IdClass(MaterialResourceId.class) public class MaterialResource { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "id_materialresource") private Integer idMaterialResource; @Id @Column(name = "id_company") private Integer idCompany; @Column(name = "name", nullable = false) private String name = ""; ... }
内容的提问来源于stack exchange,提问作者Jesús Moncada Ramírez
相关产品推荐
相关产品推荐

