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

标签 java hibernate jpa design-patterns persistence

我有三个实体:凭据、用户和管理员。 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 作为参数传递给 UserAdmin 实体(从现在起称为 PERSON) >) 包含持久存在数据库中的Credentials实体的分离副本;那么你肯定会遇到这个问题。原因是:

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

编辑:(如何合并)

如果您没有更新 PERSON 中的 Credentials,那么在合并 PERSON_DAO 时,您可以:

  1. 在合并之前暂时删除 PERSON 中的 Credentials (null)。
  2. 合并PERSON
  3. 将原始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/

相关文章:

java - 实现更改Java工作目录的效果

java - Maven 配置问题一个或多个约束尚未满足

java - 在一对多关系中获取表中的重复条目

java - 是否可以在 Spring Repository @Query 注释中动态设置模式?

java - 重复注释错误 - 但在哪里?

java - 从 InterruptedException 中找出原因

Java String to Date 格式为 “MM/dd/yyyy HH:mm:ss a” 的对象

java - 无法将类型 'java.lang.String' 的属性值转换为属性 'int' 所需的类型 'id'

java - 升级到 Spring 3.2.4 后出现错误 NoClassDefFoundError

java - JSF 2.0 和 Hibernate 错误