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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2024078/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 02:43:24  来源:igfitidea点击:

Deleting an element from one-to-many collection (Java + HIbernate + Struts)

javahibernatecollectionsstruts

提问by Peter Di Cecco

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.

我无法从数据库中删除子对象。从该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>



Excerpt from execute() method

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


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!


我只试过,session.delete(child);我只试过parent.getChildren().remove(child);和两条线,都没有成功。没有错误或抛出异常或任何类似的东西。我确信这段代码被调用了(我什System.out.println();至用来跟踪正在发生的事情),但数据库没有更新。我可以使用类似的代码添加子项,编辑现有子项的非集合属性,编辑父项的属性,所有这些都有效,只是不删除!

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

根据Hibernate FAQ我正在做正确的映射,根据这个 SO question我有正确的逻辑。我已经浏览了整个互联网,似乎找不到其他任何东西。

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
  • Java 1.4.2
  • SQL Server 2005
  • 休眠 3.0.5
  • 支柱 1.2.7
  • Apache Tomcat 5.0.28

采纳答案by Bozho

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 removeisn't working. Then even if the deleteworks, the objects are re-cascacde because they still exist in the collection. Here's what to do:

如果您尚未覆盖该equals()方法,则可能在列表中找不到该实体,因为它已被分离,现在是不同的实例。这remove就是不工作的原因。那么即使delete有效,对象也会重新层叠,因为它们仍然存在于集合中。以下是该怎么做:

  • 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
             }
        }
    }
    
  • 要么覆盖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
             }
        }
    }
    

回答by n002213f

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

我不确定是什么导致了休眠中的这种行为,您可以通过加载第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();
} ...

show the SQL generated by Hibernate

显示 Hibernate 生成的 SQL

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

Edit:

编辑:

Check out this Chapter 10. Working with objects

查看第 10 章。 使用对象

回答by Danny Groenewegen

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

在这种情况下,Child 类是逆关系的所有者,Hibernate 将查看子类的父引用来确定关系是否仍然存在。由于您没有将父项设置为空,因此关系存在并且子项可能不会被删除。尝试做

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

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

还要从父属性映射中删除 not-null="true"。

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.

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

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

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