java 如何在Hibernate中级联更新到子实体

4uqofj5v  于 2023-02-02  发布在  Java
关注(0)|答案(1)|浏览(135)

我有三个实体:凭据、用户和管理员。用户和管理员实体都有一个字段凭据,该字段使用OneToOne注解与凭据实体相关。
当通过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和user. credentials,但我收到错误"键'login_UNIQUE的重复条目' loginname '。管理实体也会发生同样的情况。
提前感谢您的帮助。

bvk5enib

bvk5enib1#

出现此错误的原因可能是merge将分离实体的内容复制到托管实体中。因此,如果您将UserAdmin实体(从现在起称为PERSON)作为参数传递给x1m1 n1 a,该实体包含数据库中持久化的Credentials实体的分离副本;那么你肯定会得到这个问题。原因是:

  1. merge将把PERSON实体变元的整个状态复制到对应的上下文管理的PERSON实体中。
    1.此副本将在PERSON参数中包含Credentials实体。
    1.由于Credentials实体是分离的,持久性管理器将假定此实体对应于尚未持久化的实体。
    1.刷新会话时,持久化上下文将使用INSERT(持久化新的Credentials)而不是UPDATE保存合并的Credentials
  2. INSERT将触发您正在获取的login字段上的重复约束冲突,因为原始Credentials记录存在,并且login值正在INSERT中使用。

编辑:(如何合并)

如果您没有在PERSON中更新Credentials,则在合并PERSON_DAO时,您可以:
1.在合并之前,暂时从PERSONnull)中删除Credentials
1.合并PERSON
1.将原始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;
    }

相关问题