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
cascade-MVSNet——CVPR-202(源码、原文、译文) cascade-MVSNet——CVPR-202(源码、原文、译文) cascade-MVSNet——CVPR-202(源码、原文、译文) cascade-MVSNet——CVPR-202(源码、原文、译文) cascade-...
资源来自pypi官网。 资源全名:django-postgres-delete-cascade-2.0a1.tar.gz
haarcascade-frontalface-alt人脸识别分类器文件
Ajax-Cascade-Ajax-Select.zip,这是一个现成的html/jquery源代码,演示了如何构建基于ajax的级联选择。,ajax代表异步javascript和xml。它是多种web技术的集合,包括html、css、json、xml和javascript。它用于创建...
opencv识别车牌haarcascade-licence-plate-rus-16stages.xml
Free~, "opencv安装目录"\sources\data\haarcascades\"你想要的都有" 相应的还有lbp,当然实际生活场景这些官方提供的,效果都不好,请自行训练! haar的误检测率很高! lbp误检测高不说,框的方式也不好,不适合...
级联式无刷双馈发电机的仿真研究Cascade brushless doubly-fed generator simulation
OpenCV人脸识别文件haarcascade-frontalface-default.xml
OpenCV做人脸检测时,haarcascade-frontalface-default.xml
Open_CASCADE学习笔记-曲面建模
haarcascade_eye_tree_eyeglasses.xml OpenVC haarcascade_frontalcatface.xml haarcascade_frontalcatface_extended.xml haarcascade_frontalface_alt.xml haarcascade_frontalface_alt_tree.xml haarcascade_...
人脸harr级联分类器保存的.xml文件,包括:haarcascade-frontalface-default.xml等文件
串级控制系统实例程序,适合于初学者!!!!!!!!!!!!
CMOS Cascade Sigma-Delta Modulators for Sensors and Telecom
Cascade Trainer GUI是可用于训练opencv特征,测试和改进级联分类器模型的程序。它使用图形界面来设置参数,并... https://amin-ahmadi.com/cascade-trainer-gui/ 该工具用来代替手动训练opencv 特征集,使用简单。
eguid专栏中javacv进阶opencv图像处理和图像识别专栏文章使用的基于haar级联分类的正面人脸特征检测
Real-time vehicle detection with foreground-based cascade classifier
In object detection, an intersection over union (IoU) threshold is required to define positives and negatives. An object detector, trained with low IoU ...https://github.com/zhaoweicai/cascade-rcnn.
基于特征共享双头Cascade_R-CNN的混凝土细观损伤特征检测.pdf