Отношение один ко многим JPA / Hibernate удаление ссылок - PullRequest
2 голосов
/ 13 апреля 2011

У меня настроена двусторонняя связь следующим образом:

class Child{
    @ManyToOne
    @JoinTable(name = "CHILDREN_WITH_PARENT", 
            joinColumns = {@JoinColumn(name = "CHILD_ID")}, 
            inverseJoinColumns = {@JoinColumn(name = "PARENT_ID")}
    )
    private Parent parent;
}

class Parent{
    @OneToMany(mappedBy="parent", cascade=CascadeType.ALL)
    Set<Child> childrens = new HashSet<Child>();

    public void persistOrMerge() {
        EntityManager em = entityManager();
        em.getTransaction().begin();
        try {
            if (em.contains(this))
                return;
            if (id == null || id == 0) {
                this.setCreatedDate(new Date());
                em.persist(this);
            } else {
                Parent prev = em.find(Parent.class, this.id);
                if (prev == null) {
                    em.persist(this);
                } else{
                    this.setCreatedDate(new Date());
                    em.merge(this);
                }
            }
            em.flush();
            em.getTransaction().commit();

        }  finally {
            em.close();

        }
    }

}

На стороне клиента у меня есть следующий код (GWT + EntityProxy)

Set<ChildProxy> children  = new HashSet<ChildProxy>();
if(childIsNew)
   child = request.create(Children.class)
else
   child = request.edit(oldChild)
children.add(child);
//If children are deleted, they are not contained in the set
//we are sending back to server
parent.setChildren(children)
parent.persistOrMerge();

Этот код работает только длядобавление новых детей.Удаление дочерних элементов из родительского не работает, даже если родительский класс получает пустой набор дочерних элементов.Связи в таблице JOIN не удаляются.

Подскажите, пожалуйста, где я что-то упускаю?

Спасибо!

Ответы [ 4 ]

6 голосов
/ 13 апреля 2011

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

Метод EntityManager.merge () возвращает фактический объединенный экземпляр, это подразумевает, что в вашем коде при выдаче

em.merge(this)

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

Если вы не думаете, что это настолько важно, ваша проблема должна быть решена путем включения удаления сирот на стороне OneToMany отношений, при условии, что дети не используются где-либо еще в других отношениях. В противном случае вам придется выполнить объединение вручную.

@OneToMany(mappedBy="parent", cascade=CascadeType.ALL, orphanRemoval=true)
Set<Child> childrens = new HashSet<Child>();

В спецификации JPA 2.0 указано, что

Ассоциации, указанные как OneToOne или OneToMany, поддерживают использование orphanRemoval. вариант. Следующие поведения применяются, когда действует orphanRemoval:

  • Если объект, который является целью отношения удалены из отношения (установив отношение к нулю или удаление сущность из отношений сбор), операция удаления будет применяться к сущности осиротел. Операция удаления применяется во время сброса операция. СиротаУдалить Функциональность предназначена для юридические лица, которые находятся в частной собственности их родительской сущностью. портативный в противном случае приложения не должны зависит от определенного порядка удаление, и не должны переназначать субъект, который был осиротел другие отношения или иным образом попытка упорствовать. Если субъект быть осиротевшим отстраненным, новым или удаленная сущность, семантика orphanRemoval не применяются.
  • Если операция удаления применяется к управляемый исходный объект, удаление операция будет каскадно целевые отношения в соответствии с правилами раздела 3.2.3, (и следовательно, не нужно указывать каскад = УДАЛИТЬ для отношения) [20]. * * +1018
1 голос
/ 24 ноября 2011
// In the entity class of Parent1 write a method to unlink parent2
public void unLinkParent2(Parent2 parent2)
{
    //remove columns from the link table, pertaining to the parent2
    getParent2Collection().remove(parent2);
    // using the parent2 object remove 'this' parent1 entity link columns
    parent2.getParent1Collection().remove(this);
}
Parent1:        Parent2:        LinkP1-P2
--------------------------------------------------
Id1(PK)         Id2(PK)         Id1 (composite PK)
name1           Name2           Id2 (composite PK)

Id1 и Id2 таблицы ссылок вместе являются первичными ключами, ссылающимися на таблицы Parent1 и Parent2.

0 голосов
/ 06 ноября 2012

Отображение ManyToOne управляет отношением - вы пометили OneToMany как отображенную посредством отношения дочернего элемента к его родительскому элементу. Это означает, что изменения в отношении принимаются только в том случае, если они объединены со стороны детей. Поскольку дочерние элементы, удаленные из списка родителей, больше не находятся в нем, слияние не может быть каскадно к ним, и любые изменения в них никогда не сохраняются в базе данных.

Как отмечали другие, удаление сирот позволит удалить всех детей, отсутствующих в списке, при слиянии. Это может быть излишним, когда все, что вы хотите, это обнулить отношения. В этом шраме вы, вероятно, можете изменить отношения так, чтобы они принадлежали родителю. Это будет гарантировать, что отношение будет обновлено, но любые изменения в удаленных дочерних элементах все равно не будут обнаружены. Единственный способ получить эти изменения - это добавить дочерних элементов к новому родительскому объекту, который будет объединен, или объединить их независимо. Если они могут существовать без родителя, лучше использовать вызов persist / merge для них напрямую.

0 голосов
/ 13 апреля 2011

С этим вопросом связано: JPA CascadeType.ALL не удаляет сирот

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...