【发布时间】:2016-06-30 16:41:11
【问题描述】:
我有以下数据库架构:
account -< account_role >- role
总结:一个account可以绑定到多个roles,而account_role是一个连接表。 roles 是预定义的,角色会在迁移中插入到数据库中。
不幸的是,在创建 hibernate 的新 account 尝试将 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找到。
【问题讨论】:
-
请发布异常的完整堆栈跟踪,以及创建和持久化帐户的代码。确保您对 account_role.role_name 没有唯一约束。
-
@JBNizet,我有以下唯一约束:
ALTER TABLE ACCOUNT_ROLE ADD CONSTRAINT ACCOUNT_ROLE_UNQ UNIQUE (USERNAME, ROLE_NAME);,添加了堆栈跟踪。 -
您没有显示帐户角色的来源。如果它们应该存在,请不要使用新角色(角色名称)。通过 ID 从数据库中获取角色(使用 findOne() 或 getOne())
-
是的,我正在使用
new,但正如您所见,role(枚举)和ID也是如此。从数据库中获取角色有意义吗? Hibernate 无法识别role字段ID? -
我几乎从不使用非生成的 ID,所以我没有太多经验。我什至不明白为什么 Hibernate 试图保存角色,因为您在关联上没有任何级联注释。但我的经验法则是你应该避免像瘟疫这样的分离对象,如果数据库中存在一行,那么你应该从 JPA 获取相应的托管实体,而不是用一个(或几个不同的)分离对象来表示它.
标签: spring hibernate spring-boot jpa spring-data-jpa