如何级联更新到 Hibernate 中的子实体
How to cascade update to child entity in Hibernate
我有三个实体:Credentials、User 和 Admin。 User 和 Admin 实体都有一个字段 credentials,它使用 OneToOne 注释与 Credentials 实体相关。
通过 entityManager.merge 更新现有的用户或管理员条目时,我在 Credentials.login 列上获得了重复的键,该列具有唯一约束。
@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.credentials,但我收到错误消息“密钥的重复条目 'loginname' login_UNIQUE。Admin 实体也是如此。
提前感谢您的帮助。
您收到此错误的原因可能是 merge
将分离实体的内容复制到托管实体中。因此,如果您将包含 detachedUser
或 Admin
实体(从现在起称为 PERSON
)作为参数传递给 merge
=73=] Credentials
实体的副本保存在数据库中;那么你肯定会遇到这个问题。这样做的原因是:
merge
会将 PERSON
实体参数的整个状态复制到相应的 context managed PERSON
实体中。
- 此副本将在
PERSON
参数中包含 Credentials
实体。
- 由于
Credentials
实体已分离,持久性管理器将假定此实体对应于尚未持久化的实体。
- 持久性上下文在刷新会话时,将使用
INSERT
保存 merged Credentials
(坚持新的 Credentials
)而不是 UPDATE
.
INSERT
将触发您正在获取的 login
字段上的重复约束违规,因为原始 Credentials
记录存在且 login
值正在使用INSERT
.
编辑:(如何合并)
如果您不更新 PERSON
中的 Credentials
,那么在 PERSON_DAO
中合并时,您可以:
- 在合并之前暂时从
PERSON
(null
) 中删除 Credentials
。
- 合并
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;
}
希望对您有所帮助。
我有三个实体:Credentials、User 和 Admin。 User 和 Admin 实体都有一个字段 credentials,它使用 OneToOne 注释与 Credentials 实体相关。
通过 entityManager.merge 更新现有的用户或管理员条目时,我在 Credentials.login 列上获得了重复的键,该列具有唯一约束。
@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.credentials,但我收到错误消息“密钥的重复条目 'loginname' login_UNIQUE。Admin 实体也是如此。
提前感谢您的帮助。
您收到此错误的原因可能是 merge
将分离实体的内容复制到托管实体中。因此,如果您将包含 detachedUser
或 Admin
实体(从现在起称为 PERSON
)作为参数传递给 merge
=73=] Credentials
实体的副本保存在数据库中;那么你肯定会遇到这个问题。这样做的原因是:
merge
会将PERSON
实体参数的整个状态复制到相应的 context managedPERSON
实体中。- 此副本将在
PERSON
参数中包含Credentials
实体。 - 由于
Credentials
实体已分离,持久性管理器将假定此实体对应于尚未持久化的实体。 - 持久性上下文在刷新会话时,将使用
INSERT
保存 mergedCredentials
(坚持新的Credentials
)而不是UPDATE
. INSERT
将触发您正在获取的login
字段上的重复约束违规,因为原始Credentials
记录存在且login
值正在使用INSERT
.
编辑:(如何合并)
如果您不更新 PERSON
中的 Credentials
,那么在 PERSON_DAO
中合并时,您可以:
- 在合并之前暂时从
PERSON
(null
) 中删除Credentials
。 - 合并
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;
}
希望对您有所帮助。