EclipseLink / JPA:在分离的对象树上合并会导致子对象中的主键冲突

时间:2017-12-05 13:40:57

标签: jpa merge eclipselink primary-key entitymanager

我遇到了JPA和通过JSON反序列化从应用程序外部传递的分离实体对象的问题。

我从JSON反序列化对象图(通过HTTP POST请求传递),然后尝试从中更新现有实体。

据我了解JPA,在对象上使用EntityManager.merge()应该自动递归(取决于cascade)附加它并为数据库中的所有对象发出UPDATE。 然而,这显然只适用于1)没有子节点的单个实体或2)对象图中最顶层的实体。

对于子实体,JPA将始终发出INSERT INTO,无论该对象是否已存在,因此会遇到主键冲突。

我做错了什么?

实施的相关部分是:

AdminResource.java

@Autowire
protected CustomerConfigDAO customerConfigDao; // wrapper for the JPA persistence

@POST
@Consumes(MediaType.APPLICATION_JSON)
public void storeConfigurationData(CustomerConfigEntity config) {
    customerConfigDao.update(config); // calls EntityManager.merge(...)
}

CustomerConfigEntity.java

@Entity
public class CustomerConfigEntity implements Serializable {

    @Id
    private String customerID;

    @OneToOne(mappedBy = "customerConfigEntity", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    private DefaultValues defaultValues;

    /* ... snip ... */

    @PrePersist
    @PreUpdate
    public void fixBackReference() {
        if(this.defaultValues != null)
            this.defaultValues.setCustomerConfigEntity(this);
    }
}

DefaultValues.java

@Entity
public class DefaultValues implements Serializable {

    @Id
    @OneToOne
    @JoinColumn(name = "customerID", referencedColumnName = "cloudID")
    @JsonIgnore
    private CustomerConfigEntity customerConfigEntity;

    /* ... snip ... */

}

有人建议放弃双向一对一关系,转而采用单向关系,但由于customerConfigEntityDefaultValues中的外键和主键,因此删除它需要我介绍一个代理键。我通过引入一个自动递增的键来实现这一点,但结果是每当CustomerConfigEntity被保存时,JPA会在DEFAULTVALUES中创建一个新记录。

1 个答案:

答案 0 :(得分:0)

我通过消除所有双向关系并用单向关系替换它来解决问题。

CustomerConfigEntity.java

public class CustomerConfigEntity implements Serializable {

   // ...

   @OneToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
   @PrimaryKeyJoinColumn(name = "customerId", referencedColumnName = "customerId")
   private DefaultValues defaultValues;

   // ...

}

请注意,此处不得使用mappedBy

DefaultValues.java

   @Id
   private String customerId;

CustomerConfigEntity有更多关系,这些关系都是@OneToMany基数。

对于那些人,我做了同样的事情但必须使用@JoinColumn而不是@PrimaryKeyJoinColumn customerId - 尽管customerId 子实体的主键的一部分。但是使用@PrimaryKeyJoinColumn导致JPA创建连接表,这不是我想要的。

然而,如果我真的需要双向关系,我仍然不知道如何解决这个问题。