Java 如何在Hibernate中将更新级联到子实体
我有三个实体:凭证、用户和管理员。用户和管理员实体都有一个字段credentials,该字段与使用OneToOne注释的credentials实体相关 当通过entityManager.merge更新现有用户或管理员条目时,我在Credentials.login列上获得了重复的密钥,该列具有唯一约束Java 如何在Hibernate中将更新级联到子实体,java,hibernate,jpa,design-patterns,persistence,Java,Hibernate,Jpa,Design Patterns,Persistence,我有三个实体:凭证、用户和管理员。用户和管理员实体都有一个字段credentials,该字段与使用OneToOne注释的credentials实体相关 当通过entityManager.merge更新现有用户或管理员条目时,我在Credentials.login列上获得了重复的密钥,该列具有唯一约束 @实体 @桌子 公共类凭据{ @身份证 @列(name=“id”,unique=true,nullable=false) @GeneratedValue(策略=GenerationType.IDEN
@实体
@桌子
公共类凭据{
@身份证
@列(name=“id”,unique=true,nullable=false)
@GeneratedValue(策略=GenerationType.IDENTITY)
私人长id;
@列(unique=true,nullable=false,length=50)
私有字符串登录;
@列(nullable=false,长度=50)
私有字符串密码;
/*********************************************
*这里有接球手和接球手
**********************************************/
}
@实体
@桌子
公共类用户{
@身份证
@列(name=“id”,unique=true,nullable=false)
@GeneratedValue(策略=GenerationType.IDENTITY)
私人长id;
/*********************************************
*此处的特定用户列
**********************************************/
@OneToOne(cascade={CascadeType.ALL})
@JoinColumn(nullable=false,name=“idCredentials”)
私人证书;
/*********************************************
*这里有接球手和接球手
**********************************************/
}
@实体
@桌子
公共类管理员{
@身份证
@列(name=“id”,unique=true,nullable=false)
@GeneratedValue(策略=GenerationType.IDENTITY)
私人长id;
/*********************************************
*这里有特定的管理员栏
**********************************************/
@OneToOne(cascade={CascadeType.ALL})
@JoinColumn(nullable=false,name=“idCredentials”)
私人证书;
/*********************************************
*这里有接球手和接球手
**********************************************/
}
我希望在调用entityManager.merge(用户)后,在相应的数据库表中更新user和user.credentials,但我得到的错误是“login\u UNIQUE”键的“replicate entry'loginname”。管理实体也是如此
提前感谢您的帮助。您可能会收到此错误的原因是
merge
将分离实体的内容复制到托管实体中。因此,如果您将作为参数传递给merge
用户或Admin
实体(从现在起称为PERSON
)包含保存在数据库中的凭据的分离副本的;那么您肯定会遇到此问题。原因是:
merge
将PERSON
实体参数的整个状态复制到相应的上下文管理的PERSON
实体中
此副本将在PERSON
参数中包含凭证
实体
由于凭证
实体已分离,因此持久性管理器将假定此实体对应于尚未持久化的实体
刷新会话时,持久化上下文将使用插入(持久化新的凭据
)而不是更新来保存合并的凭据
INSERT
将触发您正在获取的login
字段上的重复约束冲突,因为原始凭证
记录与INSERT
中使用的login
值一起存在
编辑:(如何合并)
如果您没有更新个人
中的凭证
,那么在您的个人(道
)中合并时,您可以:
在合并之前,暂时删除个人的凭证(null
)
合并个人
将原始的凭证
添加回您的新合并的人员
由于我无法访问您的DAO
代码,因此这里是前一个的伪代码:
public PERSON mergeSafely(PERSON person) {
Credentials originalCredentials = person.getCredentials();
person.setCredentials(null);
person = em.merge(person);
person.setCredentials(originalCredentials);
return person;
}
如果您还想合并凭证
,那么您应该(为了清洁起见)使用dao
层上方的服务
层。在该层中完成此操作的实用程序方法的伪代码如下所示:
public PERSON mergeCompletely(PERSON person) {
Credentials mergedCredentials = credentialsDAO.merge(person.getCredentials());
person.setCredentials(mergedCredentials);
person = personDAO.merge(person);
return person;
}
希望这能有所帮助。感谢您的澄清@Marco R。您的确是对的。我添加了调用user.setCredentials(entityManager.merge(user.getCredentials())
以在调用entityManager.merge(user)之前管理user.credentials
它解决了这个问题。但是我不喜欢这个解决方案,因为它在UserDAO中混合了对CredentialsDAO的调用。有没有更优雅的方法来解决这个问题?我的意思是,有没有一种方法可以一次性保存用户及其凭据?我只是在您的评论中添加了一个问题的答案,作为我原始答案中的编辑。谢谢为了再次回复@Marco R.My person.credentials还需要更新数据,因此我相信person.setCredentials(null);
会导致凭据不会随person一起更新。我已经编辑了答案,以包含最新的考虑因素。