If you have used Hibernate and mapped a one-to-many relationship you've probably come across the "delete orphan" feature. This feature offers cascade delete of objects orphaned by code like the following:
Preference pref = getSomePreference(); user.getPreferences().remove(pref);
In the above code, a specific Preference
is removed from a User
. With the delete orphan feature, and assuming there is an active transaction associated with a session, the preference that was removed from the user is automatically deleted from the database when the transaction commits. This feature is pretty handy, but can be tricky if you try to write clever code in you setter methods, e.g. something like this:
// Do not do this! public void setPreferences(Set newPreferences) { this.preferences = newPreferences == null ? new HashSet<Preference>() : newPreferences; }
Code like the above results in a HibernateException
with the following message if you pass null
into setPreferences
and try to save the user object:
A collection with cascade="all-delete-orphan" was no longer referenced by the owning entity instance
What is happening here is that Hibernate requires complete ownership of the preferences
collection in the User
object. If you simply set it to a new object as in the above code sample, Hibernate is unable to track changes to that collection and thus has no idea how to apply the cascading persistence to your objects! The same error will occur if you passed in a different collection, e.g.:
user.setPreferences(new HashSet<Preference>());
So the point is that Hibernate's delete orphan abstraction is leaking into your domain model object. This is pretty much unavoidable but is a leaky abstraction nonetheless that developers need to be aware of lest they run into the error mentioned above.
So how can you avoid this problem? The only sure way that I know of is to make the setter method private, since passing any new collection or null results in the "owning entity" error. This way only Hibernate will use the setter method to load up user objects (it invokes the method reflectively after setting it accessible via the Reflection API). Then you could add a method addPreference
to your code which is the public API for adding preferences. Anyone could of course use reflection to do the same thing Hibernate is doing, but then all bets are off as they are subverting your public API. For example:
public void addPreference(Preference p) { getPreferences().add(p); p.setUser(this); }
This has the nice side effect of establishing the bi-directional relationship between user and preference, assuming your model allows bi-directional navigation. You could also add a null check if you are paranoid. Removing a preference from a user is equally simple. You can write a helper method removePreference
or you could call the getter and then call remove as shown here:
user.getPreferences().remove(aPref);
Essentially, you can operate on the collection returned by getPreferences
as a normal Java collection and Hibernate will do the right thing. Since you are operating on the collection maintained and observed by Hibernate, it is able to track your changes, whereas replacing the collection wholesale makes Hibernate really mad, since it believes it is the sole proprietor of the collection, not you! For example, if you want to remove all the user's preferences you could write the following:
user.getPreferences().clear();
Note that all the above discussion refers to one-to-many relationships that specify the delete orphan cascade type; usually you will specify both "all" and "delete-orphan." In cases where you are only using the "all" cascade option, the semantics are quite different. Assuming the normal case where the "many" side of the relationship owns the relationship -- i.e. you used inverse="true"
in your mapping file or @OneToMany(mappedBy = "user")
if using annotations - then you must explicitly delete the child objects as Hibernate will only track that side of the relationship. For example, if cascade is "all" and you remove a preference from a user and then save the user, nothing happens! You would need to explicitly delete the preference object, as shown here:
// Assume only using cascade="all" and an inverse="true" mapping in User.hbm.xml user.getPreferences().remove(aPref); // does not cause database delete session.delete(aPref); // this causes the database deletion
One last thing to note in the above is that you must remove aPref
from the user, or else Hibernate will throw an exception stating that the preference would be re-saved upon cascade! So if the User
object is in the Session
, remember you need to undo both sides of the relationship for things to work properly.
相关推荐
3. **all-delete-orphan**: 这是最强大的cascade选项之一,它结合了`save-update`和`delete`的特点,并增加了一个额外的功能——当子实体与父实体之间的关联被解除时,会自动删除那些不再属于任何父实体的子实体。...
标题中的“PyPI 官网下载 | django-postgres-delete-cascade-2.0a1.tar.gz”表明这是一个从Python Package Index(PyPI)官方源获取的软件包,名为“django-postgres-delete-cascade”。这个软件包的版本是2.0a1,...
对于一对多的关系,如果希望在删除A对象时,同时删除所有相关的AA对象,可以在A.hbm.xml的`<set>`元素中设置`cascade="all-delete-orphan"`。这表示不仅在A被删除时删除所有AA,而且当AA对象被孤儿化(不再与任何A...
- `cascade="all-delete-orphan"`:结合`all`和`delete-orphan`特性,当从集合中移除对象时,会立即从数据库中删除该对象。 ### 三、持久化对象状态管理 #### 持久对象状态分类 - **Transient临时态**:仅存在于...
需要注意的是,尽管 OpenCV 提供了多种预训练的分类器(如 `haarcascade-frontalface-alt` 和 `haarcascade-frontalface-alt2`),但在实际应用中可能需要根据具体情况自行训练模型以获得更佳的性能。 在训练过程中...
cascade-MVSNet——CVPR-202(源码、原文、译文) cascade-MVSNet——CVPR-202(源码、原文、译文) cascade-MVSNet——CVPR-202(源码、原文、译文) cascade-MVSNet——CVPR-202(源码、原文、译文) cascade-...
天津大学2017级软件工程计算机视觉课程大作业,,基于改进Cascade_-Cascade-RCNN-
"haarcascade-frontalface-alt.xml"就是这样一个预训练的人脸检测模型,它是一个XML文件,存储了特征检测规则和决策树结构。 **Haar级联分类器的工作原理** 1. **特征选择**:Haar级联分类器首先通过自底向上的...
在这个场景中,"cascade-function-.rar_cascade" 提供的是一种实现省市级联功能的Java脚本,主要用于Web开发,尤其是前端部分。Dreamweaver是一款流行的Web设计和开发工具,它支持多种编程语言,包括HTML、CSS、...
标题中的“人脸锁定haarcascade-frontalface-default.xml”指的是OpenCV库中用于人脸识别的一个预训练模型文件。这个模型是基于Haar特征级联分类器的,它被广泛应用于计算机视觉领域的人脸检测任务。在Python环境下...
Ajax-Cascade-Ajax-Select.zip,这是一个现成的html/jquery源代码,演示了如何构建基于ajax的级联选择。,ajax代表异步javascript和xml。它是多种web技术的集合,包括html、css、json、xml和javascript。它用于创建...
标题中的"haarcascade-frontalface-alt.xml.zip"是一个压缩包文件,其中包含了OpenCV库的一个面部检测模型。OpenCV(开源计算机视觉库)是一个强大的工具,广泛应用于图像处理和计算机视觉领域。这个模型,"haar...
- `<set name="items"cascade="all-delete-orphan" inverse="true">` 描述了`Order`类中名为`items`的集合属性与数据库表的关系。`cascade="all-delete-orphan"`表示当父对象被删除时,所有孤儿子对象也将被删除。`...
在这个场景中,我们关注的是`haarcascade-frontalface-default.xml`文件,这是一个预训练的人脸检测模型。 `haarcascade-frontalface-default.xml`是OpenCV中的一种级联分类器,用于检测图像中的人脸。这种级联分类...
标题 "haarcascade-russian-plate-number.xml.zip" 指的是一个OpenCV库中的预训练分类器模型,专门用于检测俄罗斯车辆的车牌号码。这个压缩包包含了一个名为 "haarcascade_russian_plate_number.xml" 的文件,这是一...
stage by stage, leveraging the observation that the out- put of a detector is a good distribution for training the next higher quality detector. The resampling of progres- sively improved hypotheses ...
`org.springframework.orm.hibernate3.HibernateSystemException`: Don't change the reference to a collection with cascade="all-delete-orphan"** - **异常描述**:试图更改具有`cascade="all-delete-orphan"`...
在这个场景下,我们关注的是OpenCV中的人脸检测技术,尤其是基于Haar特征的级联分类器,这正是`haarcascade-frontalface-default.xml`文件所代表的。 Haar特征是一种用于图像分析的简单而强大的工具,由Paul Viola...
Cascade Trainer GUI是可用于训练opencv特征,测试和改进级联分类器模型的程序。它使用图形界面来设置参数,并... https://amin-ahmadi.com/cascade-trainer-gui/ 该工具用来代替手动训练opencv 特征集,使用简单。
级联式无刷双馈发电机的仿真研究Cascade brushless doubly-fed generator simulation