我有以下数据库架构:
account -< account_role >- role
总结:account
可以绑定到多个roles
,account_role
是一个连接表。预定义了roles
,并且在迁移中将角色插入到DB中。
不幸的是,在新account
创建hibernate尝试将role
插入到表中时会导致以下异常:
org.postgresql.util.PSQLException: ERROR: duplicate key value violates unique constraint "role_role_name_key"
Detail: Key (role_name)=(CUSTOMER) already exists.
如何配置关系以防止插入?
下面提到的课程:
角色
import javax.persistence.*;
import static javax.persistence.EnumType.STRING;
@Entity
@Table(name = "ROLE")
class Role {
@Id
@Column(name = "ROLE_NAME")
@Enumerated(STRING)
private RoleName role;
//getters, setters, constructors
}
和
帐户
import javax.persistence.*;
import java.util.HashSet;
import java.util.Set;
import static javax.persistence.FetchType.EAGER;
import static javax.persistence.GenerationType.SEQUENCE;
@Entity
@Table(name = "ACCOUNT")
public class Account {
@Id
@SequenceGenerator(allocationSize = 1, sequenceName = "ACCOUNT_PK_SEQ", name = "ACCOUNT_PK_SEQ")
@GeneratedValue(generator = "ACCOUNT_PK_SEQ", strategy = SEQUENCE)
@Column(name = "ID")
private Long id;
@Column(name = "USERNAME")
private String username;
@ManyToMany(fetch = EAGER)
@JoinTable(
name = "ACCOUNT_ROLE",
joinColumns = @JoinColumn(name = "USERNAME", referencedColumnName = "USERNAME"),
inverseJoinColumns = @JoinColumn(name = "ROLE_NAME", referencedColumnName = "ROLE_NAME")
)
private Set<Role> roles = new HashSet<>();
//getters, setters, constructor
}
以下是负责保存新帐户的代码:
@Transactional
public Account createNewAccount(Account account, String password) {
validator.validateNewAccount(account, password);
String email = account.getUsername().toLowerCase();
checkIfEmailAlreadyTaken(email);
LOG.info("Creating new account for username: '{}'.", account.getUsername());
account.setPassword(encodePassword(password));
account = repository.save(account);
return account;
}
Account
类的对象是从请求中自动创建的。
可以找到完整的异常堆栈跟踪here。
答案 0 :(得分:1)
问题是由
引起的@Id
@Column(name = "ROLE_NAME")
@Enumerated(STRING)
JPA规范说:
2.1.4主键和实体标识
主键(或复合主键的字段或属性)应为以下类型之一:任何Java基本类型;任何原始包装类型; java.lang.String中; java.util.Date; java.sql.Date。然而,通常,不应在主键中使用近似数字类型(例如,浮点类型)。主键使用其他类型的实体将不可移植。
因此,当您使用枚举作为id时,似乎不允许@Id和@Enumeration的组合。
使用当前代码,您只能编写与枚举RoleName具有元素一样多的角色。这些是您系统的预定义角色。 你应该在启动时做一次(或以其他方式确保它们存在)
添加注释
@Column(insertable=false, updatable=false)
到Account.roles,这会告诉JPA提供者在插入或更新帐户时不插入或更新角色。
这应该有用。