Спящий режим: удалите и добавьте тот же объект с помощью orphanRemoval, объект будет удален

#hibernate #transactions #quarkus-panache #orphan-removal

Вопрос:

У меня странное поведение с гибернацией. Мое окружение-Кваркус с щегольством, но я думаю, что на самом деле это не связано с проблемой.

Я использую простую древовидную сущность с идентификатором родителя и потомков. Мой метод перемещения только что переместил ребенка в другого родителя:

  • Я забрал ребенка у старого родителя
  • Я добавил ребенка в нового родителя

После транзакции дочерний элемент полностью удаляется, и действие добавления не учитывается.

Это нормальное поведение?

Сущность :

 @Entity(name = "Element")
@Access(AccessType.PROPERTY)
@Inheritance(strategy = InheritanceType.JOINED)
public class Element {

    private Long id;
    
    private Element parent;
    
    private List<Element> subActivities = new ArrayList<>();
    
    /////////////////////////////////////////////////////////////
    /////////////////////////////////////////////////////////////
    /////////////////// Getteur Setteur /////////////////////////
    /////////////////////////////////////////////////////////////
    /////////////////////////////////////////////////////////////
    
    @Id
    @GeneratedValue
    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }
    
    @JsonManagedReference
    @OneToMany(mappedBy = "parent", fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true)
    public List<Element> getSubActivities() {
        return this.subActivities;
    }

    public void setSubActivities(List<Element> sousactivites) {
        this.subActivities = sousactivites;
    }
    
    @JsonBackReference
    @ManyToOne()
    @JoinColumn(name = "parent", referencedColumnName = "id")
    public Element getParent() {
        return this.parent;
    }

    public void setParent(Element parent) {
        this.parent = parent;
    }

 

Моя служба :

 @ApplicationScoped
public class ElementService {

    @Inject
    ElementRepository repository;

   public static Long id1;
   public static Long id2;
   public static Long id3;

   /** Prepare the test */
   @Transactional
   public void create() {
           Element element1 = new Element();
           Element element2 = new Element();
           Element element3 = new Element();
           
           this.add(element1, element3);
           
           repository.persist(element1);
           repository.persist(element2);
           repository.persist(element3);
           id1 = element1.getId();
           id2 = element2.getId();
           id3 = element3.getId();
    }

    /** Test method */
    public void test() {

        Element element1 = repository.findById(id1);
        Element element2 = repository.findById(id2);
        Element element3 = repository.findById(id3);

        System.out.println("________________ before _____________");
        System.out.println(element1  " "  element1.getSubActivities());
        System.out.println(element2  " "  element2.getSubActivities());
        
        moveInto(element2.getId(), element3.getId());


        Element element01 = repository.findById(id1);
        Element element02 = repository.findById(id2);
        Element element03 = repository.findById(id3);
        
        System.out.println("________________ after _____________");
        System.out.println(element01  " "  element01.getSubActivities());
        System.out.println(element02  " "  element02.getSubActivities());

    }

    /** Problematic method */
    @Transactional
    public void moveInto(Long parentId, Long nodeId) {
        Element parent = repository.findById(parentId);
        Element node = repository.findById(nodeId);
        moveInto(parent, node);
    }


   void moveInto(Element parent, Element tnode) {
       this.remove(tnode);
       this.add(parent, tnode);
    }
    
    void remove(Element node) {
        if (node.getParent() != null) {
            boolean deleted = node.getParent().getSubActivities().remove(node);
            node.setParent(null);
            System.out.println("isDeleted ? : "   deleted);
        }
    }

   void add(Element parent, Element value) {
        if (parent.getSubActivities() != null) {
            boolean added = parent.getSubActivities().add(value);
            value.setParent(parent);
            System.out.println("isAdded ? : "   added);
        }
    }

}
 

Результат :

 ________________ before _____________
fr.projetlineaire.ganttonline.activity.test.Element@5213dcac [fr.projetlineaire.ganttonline.activity.test.Element@34699167]
fr.projetlineaire.ganttonline.activity.test.Element@44cbb4c2 []
isDeleted ? : true
isAdded ? : true
________________ after _____________
fr.projetlineaire.ganttonline.activity.test.Element@5213dcac []
fr.projetlineaire.ganttonline.activity.test.Element@44cbb4c2 []
 

Ответ №1:

Это может быть ошибка в режиме гибернации, для которой вам следует отправить уведомление об ошибке в службу отслеживания проблем(https://hibernate.atlassian.net) с вашим тестом case(https://github.com/hibernate/hibernate-test-case-templates/blob/master/orm/hibernate-orm-5/src/test/java/org/hibernate/bugs/JPAUnitTestCase.java), который воспроизводит проблему.

Однако я на самом деле считаю, что удаление сирот просто не работает так, как вы ожидали бы в данном конкретном случае. Проблема может заключаться в том , что вы используете mappedBy , но было бы лучше просто отправить проблему и подождать анализа вопроса командой Hibernate.