Hibernate一对多映射(外键为复合主键)插入报错求解决方案
解决方案
方案一:使用@ElementCollection简化实现(推荐)
你的user_roles表仅用于存储用户的角色列表,无额外业务字段,完全可以用Hibernate的@ElementCollection替代单独实体类,代码更简洁且避免主键冲突问题:
修改User实体类
@Entity @Table(name="users") public class User { @Id @GeneratedValue(strategy = GenerationType.UUID) @Column(name="id") private UUID id; @Column(name="name") private String name; @ElementCollection(fetch = FetchType.LAZY) @CollectionTable( name = "user_roles", joinColumns = @JoinColumn(name = "user_id", nullable = false) ) @Column(name = "role", nullable = false) @BatchSize(size=10) private Set<String> roles = new HashSet<>(); // getter、setter、添加/删除角色的方法 }
该方案会自动映射到user_roles表,无需额外的UserRole实体和主键类,完全匹配你的数据库结构,插入/更新时不会出现重复字段问题。
方案二:修正UserRole实体的关联关系(保留实体场景)
如果因业务需求必须保留UserRole实体,需修正关联逻辑,避免user_id字段被重复映射:
1. 修改UserRole实体
将单独的userId字段替换为@ManyToOne关联到User,同时调整主键类字段:
@Entity @Table(name="user_roles") @IdClass(UserRoleId.class) public class UserRole { @Id @ManyToOne(optional = false) @JoinColumn(name = "user_id", nullable = false) private User user; @Id @Column(name="role", nullable = false) private String role; // getter、setter、构造方法 }
2. 修改UserRoleId主键类
主键类字段需与实体类主键字段对应,改为User类型(Hibernate会自动处理关联主键值):
public class UserRoleId implements Serializable { private User user; private String role; // 必须重写equals()和hashCode()方法 // 构造方法、getter、setter }
3. 调整User实体的关联
去掉@JoinColumn,改用mappedBy指定关联反向字段:
@Entity @Table(name="users") public class User { // ... 其他字段不变 @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true) @BatchSize(size=10) private Set<UserRole> roles = new HashSet<>(); // 添加角色的方法示例: public void addRole(String roleName) { UserRole userRole = new UserRole(); userRole.setUser(this); userRole.setRole(roleName); this.roles.add(userRole); } }
修改后,Hibernate不会生成重复的user_id插入字段,解决参数缺失的报错问题。
错误根源
你之前的代码中,User类的@OneToMany用@JoinColumn指定了user_id,同时UserRole类又把userId作为独立主键字段,Hibernate会将两者都视为需要插入的字段,导致SQL中出现两个user_id,但你未给第二个user_id赋值,因此报错No value specified for parameter 3。
内容的提问来源于stack exchange,提问作者mkorman
相关产品推荐
相关产品推荐

