2014-07-15 4 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()

Может кто-нибудь объяснить, почему это происходит?

Я использую спящий режим 3.5.6-Final

Благодарности

UPDATE: Через некоторое время отладки я нашел код, который вызывает эту ошибку, и я должен быть случайно удалил при отправке вопроса. Я искренне извиняюсь за это.

Виновник был обычным OneToManyInverseCheck bean validator, который проверял, установлены ли отношения как для родителя, так и для ребенка. Это вызвало загрузку дополнительных объектов (детей детей) во время операции фиксации.

Entity:

@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:

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

Это может быть потому, что в removeChildWithMerge вашей коллекции дети поленился загружены и во время промывки, вызывая загрузку элементов, которые приводят к этому исключению. Вы могли бы использовать Hibernate.inititalize (obj) вместо вызова merge. С другой стороны, в removeChildWithFetch вы используете fetch, чтобы загружать коллекцию и, следовательно, элементы коллекции. Так что во время флеша элемент уже загружен, поэтому нет проблем.

+0

Почему вам нужно будет вызвать некоторую функцию для реализации, когда другие реализации JPA (и спецификация JPA) не требовать? –

+0

Я полностью согласен с Нилом. Но это был просто еще один вариант. Спасибо за указание в любом случае. – Puneetsri

Смежные вопросы