Почему слияние не каскадируется в отношениях от одного до многих - программирование
Подтвердить что ты не робот

Почему слияние не каскадируется в отношениях от одного до многих

Мой вопрос здесь почти аналогичен моему другому вопросу Явное удаление по отношениям JPA но я подумал о том, чтобы упростить его, чтобы гарантировать более подробные ответы.

Представьте, что у меня есть отношения OneToMany между родителем и дочерним элементом.

@Entity
public class Parent {
    private String name;
    @OneToMany(mappedBy="owner",cascade=CascadeType.ALL, fetch=FetchType.EAGER)
    private List<Child> children;
}
@Entity
public class Child {
    private String name;
    @ManyToOne
    private Parent owner;
}

В моем пользовательском интерфейсе я показываю список родителей. Пользователь может выбрать одного родителя, и он может редактировать список своих детей. Чтобы показать это, я использовал переменную currentParent для представления текущего родительского объекта. Пользователь может выбрать для добавления/редактирования имени детей.

После нажатия кнопки я сохраню список новых детей с помощью вызова EJB.

@ViewScoped
public class MyBean(){
    private Parent currentParent;
    @EJB
    private MyEJB myEJB;

    public void saveChanges(){
        myEJB.save(currentParent);
    }
}

Мой вызов EJB выглядит следующим образом.

@Stateless
public class MyEJB{
    @PersistenceContext(unitName = "MyPU")
    private EntityManager em;

    public void save(Parent parentNew){
        Parent pOld = em.find(entityClass,  p.getId());
        if(pOld !=null){
            pOld.setName(parentNew.getName());
            pOld.setChildren(parentNew.getChildren());
            em.merge(pOld);
        }
    }
}

Моя проблема в том, что я могу изменить имя родителя, но любые изменения в списке дочерних элементов не отражаются в БД. Он не изменяет и не выполняет какой-либо SQL для удаления/обновления/добавления дочерних элементов.

В чем может быть причина?

UPDATE

Хорошо после некоторых проб и ошибок и чтения через различные ссылки, кажется, что установка опции orphanRemoval в моем @onetomany решит мою проблему. Eclipselink автоматически удаляет строки сирот во время слияния.

Так много для сложности JPA.

@Entity
public class Parent {
    private String name;
    @OneToMany(mappedBy="owner",cascade=CascadeType.ALL, fetch=FetchType.EAGER,orphanRemoval = true)
    private List<Child> children;
}
4b9b3361

Ответ 1

Это стандартная проблема слиянием. Изменения в дочерних объектах в коллекции будут получены.

Слияние может только каскадироваться по объектам, находящимся в списке, так что изменения в объектах, не входящих в список, теряются. К сожалению, oneToMany не имеет отношения: ребенок ManyToOne делает. Таким образом, дочерние объекты должны быть объединены для изменений, которые должны быть замечены и перенесены в базу данных. Резидентные объекты являются независимыми объектами и должны быть объединены индивидуально, когда они изменены. Это или добавлено к другому родительскому/дереву для объединения.

Ответ 2

Ваш вопрос What could be the cause?. Причиной является значение content parentNew. Если parentNew является одной из следующих причин, он не будет влиять на /child/update.

  • Нет родительской и дочерней визовой справки. --- > Он будет генерировать исключение.
  • Parent значение параметра имеет нулевой или пустой список Clild Это будет вашей причиной.
  • Child не получать обновленное имя из пользовательского интерфейса.-- > Это будет вашей причиной.

Пример. Я быстро напишу. Все в порядке.

Уже существуют данные в DB

Parent                      Child
==================    =======================================
'P001', 'Parent 1'   'C002', 'Child 2', 'P001'
                     'C003', 'Child 3', 'P001'
                     'C001', 'Child 1', 'P001'

После обновления:

Parent                      Child
==================          =======================================
'P001', 'Update Parent 1'   'C002', 'Update Child 2', 'P001'
                            'C003', 'Update Child 3', 'P001'
                            'C001', 'Update Child 1', 'P001'

List<Child> clidList = new ArrayList<Child>();
Parent parent = new Parent("P001", "Update Parent 1", clidList);
Child c1 = new Child("C001", "Update Child 1", parent);
Child c2 = new Child("C002", "Update Child 2", parent);
Child c3 = new Child("C003", "Update Child 3", parent);
clidList.add(c1);
clidList.add(c2);
clidList.add(c3);

Parent existingParent = em.find(Parent.class, parent.getId());
existingParent.setName(parent.getName());
existingParent.setChildren(parent.getChildren());
em.merge(existingParent);