嵌入式主键场景下BlockAttribute报Null id generated Error求助
解决JPA保存BlockAttribute时出现"null id generated for:class BlockAttribute"错误
问题根源
你遇到的核心问题是BlockAttribute的嵌入式主键BlockAttributeID未被正确赋值:
- 嵌入式主键由
blockID和attribute两个字段共同组成,二者必须同时非空才能生成有效主键; - 虽然你提前保存Block拿到了ID,但仅设置
blockAttribute.setBlock(block)无法自动同步ID到嵌入式主键的blockID字段; - 当前实体映射存在冗余:
BlockAttribute中@ManyToOne的block与嵌入式主键里的blockID对应同一数据库字段,但未建立关联,导致JPA无法自动同步ID。
解决方案
1. 修复实体映射,用@MapsId关联主键与关联实体
修改BlockAttribute类,给@ManyToOne的block字段添加@MapsId("blockID")注解,让JPA自动将关联Block的ID同步到嵌入式主键的blockID属性:
@Data @Table(name = "block_attribute") @Entity public class BlockAttribute { @EmbeddedId BlockAttributeID blockAttributeID; @ManyToOne(fetch = FetchType.LAZY) @JsonIgnore @JoinColumn(name = "block_id") @MapsId("blockID") // 新增:关联嵌入式主键的blockID字段 Block block; String label; @Enumerated(EnumType.STRING) Type type; @Enumerated(EnumType.STRING) Unit unit; String value; @Override public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof BlockAttribute)) return false; return blockAttributeID != null && blockAttributeID.equals(((BlockAttribute) o).getBlockAttributeID()); } @Override public int hashCode() { return getClass().hashCode(); } }
2. 确保嵌入式主键的所有字段都被赋值
创建BlockAttribute时,必须初始化BlockAttributeID并设置attribute字段(主键必填项):
// 保存Block获取ID block = blockRepository.save(block); // 初始化嵌入式主键 BlockAttributeID attributeId = new BlockAttributeID(); attributeId.setAttribute("your_attribute_key"); // 必须设置主键的attribute部分 // 初始化BlockAttribute BlockAttribute blockAttribute = new BlockAttribute(); blockAttribute.setBlockAttributeID(attributeId); blockAttribute.setBlock(block); // 设置其他字段:label、type、unit、value等 // 同理处理BlockBoundary BlockBoundary blockBoundary = new BlockBoundary(); blockBoundary.setBlock(block); // 设置BlockBoundary的其他字段 // 保存子实体 blockAttributeRepository.save(blockAttribute); blockBoundaryRepository.save(blockBoundary);
3. 利用级联保存简化代码(推荐)
由于Block的@OneToMany关联已配置cascade = CascadeType.ALL,可直接将子实体添加到Block的集合中,仅保存Block即可自动级联保存子实体:
// 初始化BlockAttribute BlockAttributeID attributeId = new BlockAttributeID(); attributeId.setAttribute("your_attribute_key"); BlockAttribute blockAttribute = new BlockAttribute(); blockAttribute.setBlockAttributeID(attributeId); // 设置其他字段 // 初始化BlockBoundary BlockBoundary blockBoundary = new BlockBoundary(); // 设置BlockBoundary的其他字段 // 添加到Block集合,自动建立双向关联 block.addBlockAttributes(blockAttribute); block.addBlockBoundaries(blockBoundary); // 仅保存Block,级联保存所有关联子实体 blockRepository.save(block);
4. 优化Block的add方法(双向关联一致性)
修改Block的add方法,自动设置子实体的反向关联,避免关联不一致:
public void addBlockAttributes(BlockAttribute blockAttribute) { blockAttributes.add(blockAttribute); blockAttribute.setBlock(this); // 自动设置子实体的block引用 } public void addBlockBoundaries(BlockBoundary blockBoundary) { blockBoundaries.add(blockBoundary); blockBoundary.setBlock(this); // 自动设置子实体的block引用 }
内容的提问来源于stack exchange,提问作者Vaibhav Kumar
相关产品推荐
相关产品推荐

