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

发布于 2024-08-16 19:37:55 字数 2151 浏览 3 评论 0原文

我无法从数据库中删除子对象。在 org.apache.struts.action.Action.execute() 方法中,我从父级的 List 中删除子级,并调用 session.delete (子)。我简化了下面的代码,只包含我认为相关的内容。


Hibernate 映射

<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
  • Struts 1.2.7
  • Apache Tomcat 5.0.28

I can't delete a child object from the database. From the org.apache.struts.action.Action.execute() method, I am removing the child from the parent's List, and also calling session.delete(child). I've simplified the code below and only included what I believe to be relavent.

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>

Excerpt from execute() method

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();
} ...

I've tried with only session.delete(child); and I've tried with only parent.getChildren().remove(child); and with both lines, all without success. There are no errors or thrown exceptions or anything of the sort. I'm sure this code gets called (I've even used System.out.println(); to trace what's happening), but the database isn't updated. I can add children using similar code, edit non-collection properties of existing children, edit the parent's properties, all of that works, just not deleting!

According to the Hibernate FAQ I'm doing the mapping right, and according to this SO question I've got the right logic. I've looked all over the internet and can't seem to find anything else.

What am I doing wrong? Please help! Thanks.

Notes on versions

Everything is a few years old:

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

木落 2024-08-23 19:37:55

如果您没有重写 equals() 方法,则可能在列表中找不到该实体,因为它已被分离,现在是一个不同的实例。这就是 remove 不起作用的原因。然后,即使删除有效,对象也会重新级联,因为它们仍然存在于集合中。要做的事情如下:

  • 使用 id 覆盖 equals() (和 hashCode())方法(简单)或某种业务键(更合适)(在 stackoverflow 中搜索覆盖这两种方法的提示),并仅保留 getChildren().remove(child)
  • 迭代第一个循环,如下所示:

    迭代器 i = form.getDeleteItems().iterator();
    while(i.hasNext()){
        子孩子 = i.next();
        for (Iterator; it = Parent.getChildren().iterator();) {
             if (child.getId().equals(it.next().getId()) {
                 it.remove(); // 这会从底层集合中删除子集合
             }
        }
    }
    

If you haven't overridden the equals() method, the entity is probably not found in the list, because it has been detached, and is now a different instance. That's why the remove isn't working. Then even if the delete works, the objects are re-cascacde because they still exist in the collection. Here's what to do:

  • either override the equals() (and hashCode()) method(s), using either the id (easy) or some sort of busines key (more appropriate) (search stackoverflow for tips for overrideing these two metods), and leave only getChildren().remove(child)
  • Iterate over the collection of children in the first loop, like this:

    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
             }
        }
    }
    
独守阴晴ぅ圆缺 2024-08-23 19:37:55

我不确定是什么导致了休眠中的这种行为,您可以先加载 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>

编辑:

查看此 第 10 章. 使用对象

I'm not sure what causes this behavior in hibernate, you can get going by loading the Child first. Separately deleting the Child is not nessesary. Updated code should look like;

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();
} ...

show the SQL generated by Hibernate

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

Edit:

Check out this Chapter 10. Working with objects

木緿 2024-08-23 19:37:55

在这种情况下,Child类是逆关系的所有者,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

In this case, the Child class is the owner of the inverse relation, Hibernate will look at the parent reference of the child to determine whether the relation is still there. Since you don't set the parent to null, the relation exists and the child may not be deleted. Try doing

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

Also remove the not-null="true" from the parent property mapping.

The best thing to do when working with inverse associations, is to update both sides in Java code, that way you can continue working with the objects in memory and you don't have to worry about which side owns the relation.

A similar situation is discussed here: http://simoes.org/docs/hibernate-2.1/155.html

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文