`

A collection with cascade="all-delete-orphan" was no longer referenced by the ow

阅读更多

Let's Play "Who Owns That Collection?" With Hibernate


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.


 

分享到:
评论

相关推荐

    hibernate_配置cascade_及all-delete-orphan.doc

    3. **all-delete-orphan**: 这是最强大的cascade选项之一,它结合了`save-update`和`delete`的特点,并增加了一个额外的功能——当子实体与父实体之间的关联被解除时,会自动删除那些不再属于任何父实体的子实体。...

    PyPI 官网下载 | django-postgres-delete-cascade-2.0a1.tar.gz

    标题中的“PyPI 官网下载 | django-postgres-delete-cascade-2.0a1.tar.gz”表明这是一个从Python Package Index(PyPI)官方源获取的软件包,名为“django-postgres-delete-cascade”。这个软件包的版本是2.0a1,...

    关于Hibernate级联删除的问题.doc

    对于一对多的关系,如果希望在删除A对象时,同时删除所有相关的AA对象,可以在A.hbm.xml的`&lt;set&gt;`元素中设置`cascade="all-delete-orphan"`。这表示不仅在A被删除时删除所有AA,而且当AA对象被孤儿化(不再与任何A...

    hibernate 学习笔记3

    - `cascade="all-delete-orphan"`:结合`all`和`delete-orphan`特性,当从集合中移除对象时,会立即从数据库中删除该对象。 ### 三、持久化对象状态管理 #### 持久对象状态分类 - **Transient临时态**:仅存在于...

    haarcascade-frontalface-alt haarcascade-frontalface-alt2

    需要注意的是,尽管 OpenCV 提供了多种预训练的分类器(如 `haarcascade-frontalface-alt` 和 `haarcascade-frontalface-alt2`),但在实际应用中可能需要根据具体情况自行训练模型以获得更佳的性能。 在训练过程中...

    深度学习三维重建 cascade-MVSNet-CVPR-202(源码、原文、译文)

    cascade-MVSNet——CVPR-202(源码、原文、译文) cascade-MVSNet——CVPR-202(源码、原文、译文) cascade-MVSNet——CVPR-202(源码、原文、译文) cascade-MVSNet——CVPR-202(源码、原文、译文) cascade-...

    天津大学2017级软件工程计算机视觉课程大作业,,基于改进Cascade_-Cascade-RCNN-.zip

    天津大学2017级软件工程计算机视觉课程大作业,,基于改进Cascade_-Cascade-RCNN-

    haarcascade-frontalface-alt人脸识别分类器文件

    "haarcascade-frontalface-alt.xml"就是这样一个预训练的人脸检测模型,它是一个XML文件,存储了特征检测规则和决策树结构。 **Haar级联分类器的工作原理** 1. **特征选择**:Haar级联分类器首先通过自底向上的...

    cascade-function-.rar_cascade

    在这个场景中,"cascade-function-.rar_cascade" 提供的是一种实现省市级联功能的Java脚本,主要用于Web开发,尤其是前端部分。Dreamweaver是一款流行的Web设计和开发工具,它支持多种编程语言,包括HTML、CSS、...

    人脸锁定haarcascade-frontalface-default.xml

    标题中的“人脸锁定haarcascade-frontalface-default.xml”指的是OpenCV库中用于人脸识别的一个预训练模型文件。这个模型是基于Haar特征级联分类器的,它被广泛应用于计算机视觉领域的人脸检测任务。在Python环境下...

    Ajax-Cascade-Ajax-Select.zip

    Ajax-Cascade-Ajax-Select.zip,这是一个现成的html/jquery源代码,演示了如何构建基于ajax的级联选择。,ajax代表异步javascript和xml。它是多种web技术的集合,包括html、css、json、xml和javascript。它用于创建...

    haarcascade-frontalface-alt.xml.zip

    标题中的"haarcascade-frontalface-alt.xml.zip"是一个压缩包文件,其中包含了OpenCV库的一个面部检测模型。OpenCV(开源计算机视觉库)是一个强大的工具,广泛应用于图像处理和计算机视觉领域。这个模型,"haar...

    hibernate配置笔记

    - `&lt;set name="items"cascade="all-delete-orphan" inverse="true"&gt;` 描述了`Order`类中名为`items`的集合属性与数据库表的关系。`cascade="all-delete-orphan"`表示当父对象被删除时,所有孤儿子对象也将被删除。`...

    OpenCV人脸识别文件haarcascade-frontalface-default.xml

    在这个场景中,我们关注的是`haarcascade-frontalface-default.xml`文件,这是一个预训练的人脸检测模型。 `haarcascade-frontalface-default.xml`是OpenCV中的一种级联分类器,用于检测图像中的人脸。这种级联分类...

    haarcascade-russian-plate-number.xml.zip

    标题 "haarcascade-russian-plate-number.xml.zip" 指的是一个OpenCV库中的预训练分类器模型,专门用于检测俄罗斯车辆的车牌号码。这个压缩包包含了一个名为 "haarcascade_russian_plate_number.xml" 的文件,这是一...

    cascade r-cnn paper

    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 ...

    java 遇到的各种异常

    `org.springframework.orm.hibernate3.HibernateSystemException`: Don't change the reference to a collection with cascade="all-delete-orphan"** - **异常描述**:试图更改具有`cascade="all-delete-orphan"`...

    人脸harr级联分类器保存的.xml文件,包括:haarcascade-frontalface-default.xml等文件

    在这个场景下,我们关注的是OpenCV中的人脸检测技术,尤其是基于Haar特征的级联分类器,这正是`haarcascade-frontalface-default.xml`文件所代表的。 Haar特征是一种用于图像分析的简单而强大的工具,由Paul Viola...

    CascadeTrainerGUI_3.3.1_x64_Setup.rar

    Cascade Trainer GUI是可用于训练opencv特征,测试和改进级联分类器模型的程序。它使用图形界面来设置参数,并... https://amin-ahmadi.com/cascade-trainer-gui/ 该工具用来代替手动训练opencv 特征集,使用简单。

    Cascade-brushless-doubly-fed-generator-simulation._brushless_bru

    级联式无刷双馈发电机的仿真研究Cascade brushless doubly-fed generator simulation

Global site tag (gtag.js) - Google Analytics