Удаление элемента из коллекции «один ко многим» (Java + HIbernate + Struts) - PullRequest
5 голосов
/ 08 января 2010

Я не могу удалить дочерний объект из базы данных. Из метода org.apache.struts.action.Action.execute() я удаляю дочерний элемент из родительского List, а также вызываю session.delete(child). Я упростил приведенный ниже код и включил в него только то, что считаю относительным.


Hibernate Mapping

<class 
    name="xxx.xxx.hibernate.Parent" 
    table="parent">

    ...

    <list
        name="children"
        cascade="all,delete-orphan"
        lazy="true"
        inverse="true">

        <key column="parent_id"/>
        <index column="list_index"/>
        <one-to-many class="xxx.xxx.hibernate.Child"/>
    </list>
</class>

<class 
    name="xxx.xxx.hibernate.Child" 
    table="child">

    ...

    <many-to-one
        name="parent"
        class="xxx.xxx.hibernate.Parent"
        not-null="true"
        column="parent_id" />

</class>


Выдержка из метода execute ()

Transaction tx = session.beginTransaction();  //session is of type org.hibernate.Session

try {
    Parent parent = (Parent) session.get(Parent.class, getParentId());

    Iterator i = form.getDeleteItems().iterator();  //form is of type org.apache.struts.action.ActionForm
    while(i.hasNext()){
        Child child = (Child) i.next();
        session.delete(child);
        parent.getChildren().remove(child); //getChildren() returns type java.util.List
    }

    session.saveOrUpdate(parent);
    tx.commit();
} ...


Я пробовал только с session.delete(child); и пробовал только с parent.getChildren().remove(child); и с обеими строками, но все безуспешно. Там нет ошибок или выброшенных исключений или что-то в этом роде. Я уверен, что этот код вызывается (я даже использовал System.out.println(); для отслеживания происходящего), но база данных не обновляется. Я могу добавлять детей, используя подобный код, редактировать несобственные свойства существующих потомков, редактировать свойства родителя, все это работает, только не удаляя!

Согласно Hibernate FAQ Я правильно делаю отображение, и согласно этот ТАК вопрос У меня правильная логика. Я просмотрел весь интернет и, похоже, больше ничего не нашел.

Что я делаю не так? Пожалуйста помоги! Спасибо.


Примечания к версии

Все несколько лет:

  • Java 1.4.2
  • SQL Server 2005
  • Hibernate 3.0.5
  • Распорки 1.2.7
  • Apache Tomcat 5.0.28

Ответы [ 3 ]

6 голосов
/ 08 января 2010

Если вы не переопределили метод equals(), сущность, вероятно, не найдена в списке, поскольку она была отсоединена и теперь является другим экземпляром. Вот почему remove не работает. Тогда даже если delete сработает, объекты будут повторно каскадными, потому что они все еще существуют в коллекции. Вот что нужно сделать:

  • либо переопределяет метод (ы) equals()hashCode()), используя либо id (простой), либо какой-либо другой ключ (более подходящий) (поиск в стеке для получения подсказок по переопределению этих двух методов) и оставить только getChildren().remove(child)
  • Перебор коллекции дочерних элементов в первом цикле, например:

    Iterator<Child> i = form.getDeleteItems().iterator();
    while(i.hasNext()){
        Child child = i.next();
        for (Iterator<Child> it = parent.getChildren().iterator();) {
             if (child.getId().equals(it.next().getId()) {
                 it.remove(); // this removes the child from the underlying collection
             }
        }
    }
    
1 голос
/ 08 января 2010

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

Transaction tx = session.beginTransaction();  //session is of type org.hibernate.Session

try {
    Parent parent = (Parent) session.get(Parent.class, getParentId());

    Iterator i = form.getDeleteItems().iterator();  //form is of type org.apache.struts.action.ActionForm
    while(i.hasNext()){
        Child child = (Child) session.get(Chile.class, ((Child) i.next()).getChildId());
        parent.getChildren().remove(child); //getChildren() returns type java.util.List
    }

    session.saveOrUpdate(parent);
    tx.commit();
} ...

показать SQL, сгенерированный Hibernate

<property name="show_sql">true</property>
<property name="format_sql">true</property>

Edit:

Проверьте это Глава 10. Работа с объектами

0 голосов
/ 08 января 2010

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

parent.getChildren().remove(child);
child.parent = null; 
session.delete(child);

Также удалите not-null = "true" из отображения родительского свойства.

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

Подобная ситуация обсуждается здесь: http://simoes.org/docs/hibernate-2.1/155.html

...