【发布时间】:2018-05-19 04:45:27
【问题描述】:
我对 JPA 和通过 JSON 反序列化从应用程序外部传递的分离实体对象有疑问。
我从 JSON 反序列化对象图(通过 HTTP POST 请求传递),然后尝试从中更新现有实体。
据我了解 JPA,在对象上使用 EntityManager.merge() 应该自动且递归地(取决于 cascade)附加它并对树中所有对象的数据库发出更新。
然而,这显然只适用于 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 ... */
}
有人建议放弃双向一对一关系,转而采用单向关系,但由于 customerConfigEntity 既是外键又是 DefaultValues 中的主键,删除它需要我引入代理键。我通过引入一个自动递增的键来做到这一点,但结果是每当保存 CustomerConfigEntity 时,JPA 都会在 DEFAULTVALUES 中创建一个新记录。
【问题讨论】:
-
显示更新方法并尝试向其中添加一些调试语句以显示您正在合并的对象图中的内容。 Merge 有望在这个简单的用例中工作,并且 EclipseLink 的单元测试表明它可以工作。尝试将 EclipseLink 日志记录设置为 Finest,并查看它在执行合并时是否查询您的实体。一个快速的解决方法是在更新调用中对实体执行查找操作,因为无论如何任何 JPA 提供者都必须这样做。
标签: jpa merge eclipselink primary-key entitymanager