удаление сущности в отношениях OneToMany

#java #hibernate #jpa

#java #переход в спящий режим #jpa

Вопрос:

Мне трудно понять, какие минимальные усилия необходимы с моей стороны для удаления сущности из отношений OneToMany. Я нахожу много примеров, просто добавляющих сущности в эти наборы (и это работает нормально), но удаление сущностей найти гораздо сложнее.

У меня есть следующий класс:

 @Entity
public class Product {
    ... 
    OneToMany(mappedBy="product", orphanRemoval=true,
              cascade={CascadeType.DETACH,CascadeType.MERGE,CascadeType.PERSIST,CascadeType.REFRESH},fetch=FetchType.EAGER)
    Set<Expert> experts = new HashSet<Expert>();
    ...
}

@Entity
public class Expert {
    ...
    @ManyToOne(optional=false)
    Product product;

    @ManyToOne(optional=false)
    Person person;

    ...
}
  

(Person похож на Product)

У меня он заполнен продуктами и экспертами. Я хочу удалить эксперта из списка продуктов, чтобы экспертный объект был полностью удален. Я ожидал бы, что либо следующего кода будет достаточно:

 Product aProduct = findAProduct(...);
Expert anExpert aProduct.getExperts.get(...); // Just get the first expert that I want removed
EntityManager em = entityManager();

  em.getTransaction().begin();
  aProduct.getExperts().remove(anExpert);
  em.merge(aProduct);
  em.getTransaction().commit();
  

или:

   em.getTransaction().begin();
  em.remove(anExpert);
  em.getTransaction().commit();
  

Это слишком упрощенно? Что делает JPA и что я должен сделать сам? Я уже решал эту проблему раньше, просто используя запросы, но я ожидаю, что JPA сможет сделать это за меня.

Комментарии:

1. Вы пробовали эти два метода? Что это дает?

Ответ №1:

Попробуйте:

 em.getTransaction().begin();
aProduct = em.merge(aProduct);
aProduct.getExperts().remove(anExpert);    
em.getTransaction().commit();
  

Проблема связана с операцией слияния, а не с удалением.

Ответ №2:

Исходя из моего прошлого опыта, удаление дочернего элемента в двунаправленных отношениях родитель-потомок в режиме гибернации может быть очень сложным.

Обычно я использую вместо этого однонаправленное отображение, т. Е. Продукт не содержит набор экспертов. Но вы можете реализовать средство получения, чтобы получить всех экспертов, используя вызов Hibernate. Преимущества заключаются в:

  1. упрощение сопоставления
  2. упрощение кодирования
  3. управляемое поведение

Вы всегда можете вернуться и реализовать кэширование или быструю выборку на более позднем этапе. И большую часть времени они являются ненужной предварительной оптимизацией.

Ответ №3:

Способ заставить его работать заключался в следующем:

 EntityManager em = entityManager();
// Retrieve the expert in the new EntityManager context 
Expert expertToDelete = em.find(Expert.class, anExpert.id);

em.getTransaction().begin();
expertToDelete.getProduct().getExperts().remove(expertToDelete);
expertToDelete.getPerson().getExperts().remove(expertToDelete);
em.remove(expertToDelete);
em.getTransaction().commit();
  

Вполне может быть, что вместо получения эксперта с помощью find вы можете использовать merge() вместо anExpert, но, похоже, вышеприведенное работает.