从一对多集合中删除元素(Java + HIbernate + Struts)

时间:2010-01-07 22:14:03

标签: java hibernate collections struts

我无法从数据库中删除子对象。我从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我正在进行映射,并根据this SO question我有正确的逻辑。我看了整个互联网,似乎找不到任何其他东西。

我做错了什么?请帮忙!感谢。


版本说明

一切都有几年了:

  • Java 1.4.2
  • SQL Server 2005
  • Hibernate 3.0.5
  • Struts 1.2.7
  • Apache Tomcat 5.0.28

3 个答案:

答案 0 :(得分:6)

如果您没有覆盖equals()方法,则可能在列表中找不到该实体,因为它已被分离,现在是另一个实例。这就是remove无效的原因。然后,即使delete有效,对象也会重新进行cascacde,因为它们仍然存在于集合中。这是做什么的:

  • 使用equals()(简单)或某种商务密钥(更合适)覆盖hashCode()(和id)方法(搜索stackoverflow提示覆盖这两个方法),只留下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 :(得分:1)

我不确定是什么原因造成hibernate中的这种行为,你可以先加载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();
} ...

显示Hibernate生成的SQL

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

修改

查看此Chapter 10. Working with objects

答案 2 :(得分:-2)

在这种情况下,Child类是反向关系的所有者,Hibernate将查看子进程的父引用,以确定关系是否仍然存在。由于您未将父级设置为null,因此存在关系,并且可能不会删除子级。尝试做

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

同时从父属性映射中删除not-null =“true”。

使用反向关联时最好的做法是更新Java代码中的双方,这样您就可以继续使用内存中的对象,而不必担心哪一方拥有该关系。< / p>

此处讨论了类似的情况:http://simoes.org/docs/hibernate-2.1/155.html