2014-07-15 2 views
2

양방향 연관에서 하위 요소를 제거하려고합니다. 필자의 말은 Employee 인스턴스를 쿼리 한 다음 getChildren() 메서드를 사용하여 연결된 자식을 가져 오는 경우 부모 및 자식 레코드가 모두 관리된다는 것입니다. 이제 child.setParent(null)parent.getChildren().remove(child)을 호출하면 트랜잭션이 커밋 될 때 두 업데이트가 유지되어야하지만 자식 요소에 병합을 호출하거나 쿼리로 자식을 페치하지 않는 한 org.hibernate.AssertionFailure: collection [org.rand.model.Employee.children] was not processed by flush() 예외가 발생합니다.컬렉션이 flush()에 의해 처리되지 않았습니다.

누군가가 왜 그런지 설명 할 수 있습니까? 디버깅 동안 나는이 오류를 일으키는 코드를 발견하고 내가 실수로이 질문을 게시하는 동안 제거해야한다 후 :

나는

UPDATE

3.5.6-최종

감사를 최대 절전 모드 사용하고 있습니다. 진심으로 사과드립니다.

부모와 자녀 모두에 관계가 설정되어 있는지 확인하는 커스텀bean validator입니다. 이것은 커밋 작업 중 추가 엔터티 (자식 하위)로드를 트리거했습니다.

법인 :

@Entity 
public class Employee { 

    @Id 
    @GeneratedValue(strategy=GenerationType.TABLE) 
    private int id; 

    @Version 
    private int version; 

    private String name; 

    @ManyToOne 
    private Employee parent; 

    @OneToMany(mappedBy="parent") 
    @OneToManyInverseCheck(inverseFieldName="parent") 
    private List<Employee> children; 

    //get/set methods ommitted 
} 

간단한 JUnit을 : 당신의 자식 컬렉션이 예외가 발생 항목의 로딩을 트리거,로드 및 플러시 동안 게으른 때문에 removeChildWithMerge에

public class JPAUpdate { 

    private static EntityManagerFactory emf; 
    private EntityManager em; 

    @BeforeClass 
    public static void init() { 
     emf = Persistence.createEntityManagerFactory("myapp-db"); 
    } 

    @Before 
    public void setUp() throws Exception { 
     em = emf.createEntityManager(); 
    } 

    @Test 
    public void removeChildWithMerge() { 
     em.getTransaction().begin(); 
     Employee e = em.createQuery("from Employee e where e.children is not empty order by e.id asc", Employee.class).getResultList().get(0); 

     Employee child = e.getChildren().get(0); 

     child.setParent(null); 
     e.getChildren().remove(child); 

     // removing this merge causes org.hibernate.AssertionFailure: collection [org.rand.model.Employee.children] was not processed by flush() 
     em.merge(child); 
     em.getTransaction().commit(); 
    } 

    @Test 
    public void removeChildWithFetch() { 
     em.getTransaction().begin(); 
     Employee e = em.createQuery("from Employee e left join fetch e.children where e.children is not empty order by e.id asc", Employee.class).getResultList().get(0); 

     Employee child = e.getChildren().get(0); 
     child.setParent(null); 
     e.getChildren().remove(child); 
     //em.merge(child); - no merge needed 
     em.getTransaction().commit(); 
    } 

    @Test 
    public void removeChild() { 
     em.getTransaction().begin(); 
     Employee e = em.createQuery("from Employee e left join fetch e.children where e.children is not empty order by e.id asc", Employee.class).getResultList().get(0); 

     Employee child = e.getChildren().get(0); 
     child.setParent(null); 
     e.getChildren().remove(child); 
     //em.merge(child); - no merge needed 
     em.getTransaction().commit(); 
    } 
} 
+0

관리해야하므로 "em.contains()"를 선택하십시오. 관리되는 경우에는 JPA 스펙에 의해 병합을 호출 할 필요가 없습니다. 그것이 관리되지 않는다면 당신은 왜 Hibernate가 관리되지 않는 객체를 나눠주고 있는지에 대한 질문을해야한다 ... –

답변

4

그것은있을 수 있습니다. 당신은 merge를 호출하는 대신 Hibernate.inititalize (obj)를 사용할 수있다. 반면에 removeChildWithFetch에서는 fetch를 사용하여 콜렉션을 열심히로드하여 컬렉션 항목을로드합니다. 플러시 중에 항목이 이미로드되어 있으므로 아무런 문제가 없습니다.

+0

다른 JPA 구현 (그리고 JPA 스펙)이 구현되지 않을 때 구현 관련 함수를 호출해야하는 이유는 무엇인가? 을 요구한다? –

+0

나는 Neil에 완전히 동의한다. 그러나 그것은 또 다른 옵션이었다. 어쨌든 지적 해 주셔서 감사합니다. – Puneetsri