2014-05-25 3 views
2

eclipselink를 사용하여 기본 JPA 설정을 수행 중입니다. 나는 물건의 재고량을 관리하는 주체가있다. 이 항목의 재고 내역을 추적하고 싶으므로 모든 업데이트를 통해 새로운 기록 항목을 만들 수도 있습니다.EntityManager.merge()가 관련 엔티티를 지속하지 않음

문제는 새로운 History 엔터티를 @PreUpdate 메서드의 히스토리 목록에 추가 할 때 Wine 엔터티와 함께 ​​유지되지 않습니다. merge() 또는 @PrePersist 메서드를 호출하기 전에 수동으로 History 엔터티를 추가하면 예상대로 작동합니다. 세터의 역사 항목을 추가하여 나는 현재 해결이 History.java

@Entity 
public class History implements Serializable { 

    @Id 
    @GeneratedValue 
    private long id; 

    @Column 
    private int oldAmount; 

    @Column 
    private int newAmount; 

    @ManyToOne(cascade = CascadeType.ALL) 
    private Wine wine; 

    //getters & setters 
} 

Wine.java

@Entity 
public class Wine implements Serializable { 

    @Id 
    @GeneratedValue 
    private long id; 

    @Transient 
    private int oldAmount; 

    @Column 
    private int amount; 

    @OneToMany(mappedBy = "wine", cascade = CascadeType.ALL) 
    private List<AmountHistory> history; 

    //getters & setters 

    @PostLoad 
    @PostUpdate 
    @PostPersist 
    private void onLoad() { 

     oldAmount = amount; 
    } 

    @PrePersist 
    private void onPersist() { 

     final History history = new History(); 
     history.setOldAmount(0); 
     history.setNewAmount(amount); 
     history.setWine(this); 

     this.history = new ArrayList<>(); 

     this.history.add(history); 
    } 

    @PreUpdate 
    private void onUpdate() { 

     if (oldAmount != amount) { 
      final History history = new History(); 
      history.setOldAmount(oldAmount); 
      history.setNewAmount(amount); 
      history.setWine(this); 

      this.history.add(history); 
     } 
    } 
} 

:

다음

내 코드입니다 금액에 대한 방법이지만, 나는 또한 Hist를 만들기 때문에이 해결책에 의해 확신을 못한다. ory 엔티티가 호출되지 않을 때 merge()이 호출됩니다.

이 문제를 해결하려면 무엇을해야합니까? 아니면 왜 이런 일이 일어 났는지 설명 할 수 있습니까?

+0

외래 키가 없습니다. 두 테이블 간의 관계를 만들려면 소유자 테이블 (기록)에 외래 키 열이 있어야합니다. – Kalyan

+0

병합은 지속성 및 업데이트를 모두 관리 할 수 ​​있습니다. 일시적인 인스턴스 인 경우 엔터티를 유지하고 관리되는 인스턴스를 반환하고, 분리 된 경우 업데이트 된 인스턴스를 업데이트하고 반환합니다. 어쩌면 당신은 일시적인 인스턴스에서 merge를 호출하고 있으므로 prepersist 핸들러 만 호출되고있을 것입니다. – Shailendra

답변

1

JPA 스펙의 섹션 3.5 : "일반적으로, 휴대용 애플리케이션의 라이프 사이클에있어서의 EntityManager 또는 조회 작업 액세스 다른 엔티티 인스턴스를 호출하거나 동일한 영속 컨텍스트 내의 관계를 수정하지 않아야 . 라이프 사이클 콜백 메소드는 호출 된 엔티티의 비 관계 상태를 수정할 수 있습니다. "

그래서 preUpdate 콜백 내에서 관계를 수정하지 말아야합니다. JPA는 수동으로 호출하지 않고 병합이 다시 발생하도록 트리거하는 방법을 제공하지 않습니다. - JPA는 병합이 이미 발생하고 관계 위에 계단식으로 연결된 후에 발생하기 때문에이 경우에는 의도대로 작동하지 않습니다.

해결 방법은 접근 자 메서드를 사용하여 이미 변경된 사항을 추적하는 것입니다. oldAmount를 추적하는 대신 새 기록 인스턴스를 추가하십시오. 이 방법을 사용하면 병합이 변경된 금액과 관계를 결정합니다.

1

History 엔티티/테이블에 외래 키 열을 추가하여 아래의 두 테이블 간의 관계를 만들어야합니다.

@Entity 
public class History implements Serializable { 

    @Id 
    @GeneratedValue 
    private long id; 

    @Column(name="WINE_ID", updateable=false, insertable=false) 
    private long wineId; 

    @Column 
    private int oldAmount; 

    @Column 
    private int newAmount; 

    @ManyToOne(cascade = CascadeType.ALL) 
    @JoinColumn(name="WINE_ID", referencedColumnName="ID") 
    private Wine wine; 

    //getters & setters 
} 
+0

Eclipselink는 정상적인 상황에서 관련 엔티티를 계속 유지/업데이트하므로 테이블 간의 관계를 올바르게 관리합니다. @PreUpdate 메서드 내에서 History를 추가 할 때 작동하지 않습니다. – l2p

+0

나는 알고있다. Wine 엔터티가 History와 함께 업데이트/지속되지 않는 이유는 '@ JoinColumn'을 사용하여 History에 지정된 외래 키 관계가 없기 때문입니다. 조인 관계를 지정하지 않으면 기본적으로 모든 JPA 구현은 항상 올바르지 않을 수있는 기본 키를 사용합니다.나는 대답에서 언급 한 것처럼'@ JoinColumn'을 사용하여 외래 키 관계를 지정해 보라고 제안합니다. – Kalyan

+1

나는 그것을 시도했다, 그것은 didnt한다 일. 그리고 나는 와인을 갱신/지속시키고 그것이 역사에 계단식으로 올 것을 기대해야한다고 분명히해야합니다. – l2p

관련 문제