2017-12-05 4 views
1

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에 새 레코드를 생성합니다.

+0

업데이트 방법을 표시하고 디버깅 문을 추가하여 병합중인 개체 그래프에있는 내용을 표시하십시오. Merge는이 간단한 사용 케이스에서 작동 할 것으로 예상되며 EclipseLink는이를 보여주는 단위 테스트를 가지고 있습니다. EclipseLink 로깅을 Finest로 설정하고 병합을 수행 할 때 엔티티를 쿼리하는지보십시오. JPA 제공자가 어쨌든 그렇게해야 할 것이기 때문에 신속한 수정은 갱신 호출 내의 엔티티에 대해 찾기 조작을 수행하는 것입니다. – Chris

답변

0

모든 양방향 관계를 제거하고 단방향으로 대체하여 문제를 해결했습니다. CustomerConfigEntity.java에서

하나는 여기 mappedBy를 사용해서는 안

public class CustomerConfigEntity implements Serializable { 

    // ... 

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

    // ... 

} 

참고. DefaultValues.java에서

:

@Id 
    private String customerId; 

CustomerConfigEntity@OneToMany 카디널리티 모두 몇 가지 더 관계를 맺고있다. 사람들을 위해

, 나는 같은 일을했지만 customerId에 대한 @JoinColumn 대신 @PrimaryKeyJoinColumn를 사용했다 - customerId 아이 엔티티의 기본 키의 일부라는 사실에도 불구하고. 그러나 @PrimaryKeyJoinColumn을 사용하면 JPA에서 조인 테이블을 만들었는데, 이는 내가 원한 것이 아닙니다.

그러나 실제로 양방향 관계가 필요하다면 어떻게 해결해야할지 모르겠다.

관련 문제