JPA 및 응용 프로그램 외부에서 JSON 비 직렬화를 통해 전달 된 분리 된 객체에 문제가 있습니다.EclipseLink/JPA : 분리 된 객체 트리에서 병합하면 하위 객체의 기본 키 위반이 발생합니다.
JSON (HTTP POST 요청을 통해 전달됨)에서 객체 그래프를 비 직렬화 한 다음 기존 객체를 업데이트하려고합니다.
JPA를 이해하는 한 객체에 EntityManager.merge()
을 사용하면 자동으로 (재귀 적으로) cascade
에 따라 첨부하고 트리의 모든 객체에 대해 DB에 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 ... */
}
구현의 중요한 부분이있다
누군가가 단방향으로 1 대 1로 양방향 관계를 끊도록 제안했으나 customerConfigEntity
이 외국이고 기본 키가 DefaultValues
이기 때문에이를 제거하려면 대리 키를 입력해야합니다. 자동 증분 키를 도입하여이 작업을 수행했지만 CustomerConfigEntity
이 저장 될 때마다 JPA가 DEFAULTVALUES에 새 레코드를 생성합니다.
업데이트 방법을 표시하고 디버깅 문을 추가하여 병합중인 개체 그래프에있는 내용을 표시하십시오. Merge는이 간단한 사용 케이스에서 작동 할 것으로 예상되며 EclipseLink는이를 보여주는 단위 테스트를 가지고 있습니다. EclipseLink 로깅을 Finest로 설정하고 병합을 수행 할 때 엔티티를 쿼리하는지보십시오. JPA 제공자가 어쨌든 그렇게해야 할 것이기 때문에 신속한 수정은 갱신 호출 내의 엔티티에 대해 찾기 조작을 수행하는 것입니다. – Chris