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

时间:2019-05-16 19:37:19

标签: java hibernate

我有三个实体:凭证,用户和管理员。 User和Admin实体都具有字段凭据,该字段凭据使用OneToOne注释与Credentials实体相关。

在更新现有的User或Admin条目时,通过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,但是我收到错误消息“ keyin_UNIQUE的重复条目'loginname'。对于Admin实体也是如此。”

在此先感谢您的帮助。

1 个答案:

答案 0 :(得分:1)

您可能会收到此错误的原因是由于merge将分离实体的内容复制到托管实体中。因此,如果您将包含分离mergeUser实体(从现在起称为Admin)作为参数传递给PERSON > Credentials实体的副本保留在数据库中;那么您肯定会遇到这个问题。原因是:

  1. merge会将PERSON实体参数的整个状态复制到相应的上下文托管 PERSON实体中。
  2. 此副本将在Credentials参数内包含PERSON实体。
  3. 由于Credentials实体已分离,因此持久性管理器将假定该实体对应于尚未持久的实体。
  4. 在刷新会话时,持久性上下文将使用Credentials(坚持使用新的INSERT)而不是{{ 1}}。
  5. Credentials将在您获得的UPDATE字段上触发重复约束约束,因为原始INSERT记录存在,而login值在{ {1}}。

编辑:(如何合并)

如果您不更新Credentials中的login,那么在合并INSERT时,您可以:

  1. 在合并之前,暂时从CredentialsPERSON)中删除PERSON_DAO
  2. 合并Credentials
  3. 将原始PERSON添加回您的新合并的 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

希望这会有所帮助。