我有三个实体:凭据、用户和管理员。 User 和 Admin 实体都有一个字段凭据,该字段与使用 OneToOne 注释的 Credentials 实体相关。
当通过entityManager.merge更新现有的用户或管理员条目时,我在Credentials.login列上获得了重复的 key ,该列具有唯一的约束。
@Entity
@Table
public class Credentials {
@Id
@Column(name="id", unique=true, nullable=false)
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(unique=true, nullable=false, length=50)
private String login;
@Column(nullable=false, length=50)
private String password;
/*********************************************
* getters and setters here
**********************************************/
}
@Entity
@Table
public class User{
@Id
@Column(name="id", unique=true, nullable=false)
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
/*********************************************
* Specific user columns here
**********************************************/
@OneToOne(cascade = {CascadeType.ALL})
@JoinColumn(nullable=false, name = "idCredentials")
private Credentials credentials;
/*********************************************
* getters and setters here
**********************************************/
}
@Entity
@Table
public class Admin{
@Id
@Column(name="id", unique=true, nullable=false)
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
/*********************************************
* Specific admin columns here
**********************************************/
@OneToOne(cascade = {CascadeType.ALL})
@JoinColumn(nullable=false, name = "idCredentials")
private Credentials credentials;
/*********************************************
* getters and setters here
**********************************************/
}
我希望在调用entityManager.merge(user)后在各自的数据库表中更新user和user.credentials,但我收到错误“重复条目'loginname'键'login_UNIQUE”。管理实体也会发生同样的情况。
预先感谢您的帮助。
最佳答案
您可能收到此错误的原因是merge
将分离实体的内容复制到托管实体中。因此,如果您将 merge
作为参数传递给 User
或 Admin
实体(从现在起称为 PERSON
) >) 包含持久存在数据库中的Credentials
实体的分离副本;那么你肯定会遇到这个问题。原因是:
merge
会将PERSON
实体参数的整个状态复制到相应的上下文管理PERSON
实体中。- 此副本将在
PERSON
参数内包含Credentials
实体。 - 由于
Credentials
实体已分离,持久性管理器将假定该实体对应于尚未持久化的实体。 - 持久化上下文在刷新 session 时,将使用
INSERT
保存合并Credentials
(保留新的Credentials
)而不是更新
。 INSERT
将触发您获取的login
字段上的重复约束违规,因为原始Credentials
记录与一起存在
值。INSERT
中使用的 >login
编辑:(如何合并)
如果您没有更新 PERSON
中的 Credentials
,那么在合并 PERSON_DAO
时,您可以:
- 在合并之前暂时删除
PERSON
中的Credentials
(null
)。 - 合并
PERSON
。 - 将原始
Credentials
添加回您的新合并的PERSON
由于我无法访问您的 DAO
代码,这里是前面的伪代码:
public PERSON mergeSafely(PERSON person) {
Credentials originalCredentials = person.getCredentials();
person.setCredentials(null);
person = em.merge(person);
person.setCredentials(originalCredentials);
return person;
}
如果您还想合并Credentials
,那么您应该(为了简洁起见)使用dao
层之上的service
层。在该层中完成此操作的实用方法的伪代码如下所示:
public PERSON mergeCompletely(PERSON person) {
Credentials mergedCredentials = credentialsDAO.merge(person.getCredentials());
person.setCredentials(mergedCredentials);
person = personDAO.merge(person);
return person;
}
希望这有帮助。
关于java - 如何在 Hibernate 中级联更新子实体,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56175515/