从一对多集合中删除元素 (Java + HIbernate + Struts)
我无法从数据库中删除子对象。在 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
如果您没有重写
equals()
方法,则可能在列表中找不到该实体,因为它已被分离,现在是一个不同的实例。这就是remove
不起作用的原因。然后,即使删除有效,对象也会重新级联,因为它们仍然存在于集合中。要做的事情如下:id
覆盖equals()
(和hashCode()
)方法(简单)或某种业务键(更合适)(在 stackoverflow 中搜索覆盖这两种方法的提示),并仅保留getChildren().remove(child)
迭代第一个循环,如下所示:
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 theremove
isn't working. Then even if thedelete
works, the objects are re-cascacde because they still exist in the collection. Here's what to do:equals()
(andhashCode()
) method(s), using either theid
(easy) or some sort of busines key (more appropriate) (search stackoverflow for tips for overrideing these two metods), and leave onlygetChildren().remove(child)
Iterate over the collection of children in the first loop, like this:
我不确定是什么导致了休眠中的这种行为,您可以先加载
Child
来开始。单独删除Child
是没有必要的。更新后的代码应该如下所示;显示 Hibernate 生成的 SQL
编辑:
查看此 第 10 章. 使用对象
I'm not sure what causes this behavior in hibernate, you can get going by loading the
Child
first. Separately deleting theChild
is not nessesary. Updated code should look like;show the SQL generated by Hibernate
Edit:
Check out this Chapter 10. Working with objects
在这种情况下,Child类是逆关系的所有者,Hibernate将查看子类的父引用来确定该关系是否仍然存在。由于您没有将父项设置为 null,因此关系存在并且子项可能不会被删除。尝试
同时从父属性映射中删除 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
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