I've a Set in my Parent entity as below:
Class Parent {
@OneToMany(mappedBy = parent, cascade = CasacadeType.ALL)
Set<Child> children;
}
Class Child {
@Column(nullable=false)
@ManyToOne
Parent parent;
}
Now event if I do a remove() operation on the Set for one of its element it doesn't actually get removed.
Another possible cause for such a failure might be:
A custom implementation of equals()
and hashCode()
which relies on properties that can change over time.
If such a property is modified after the object was added to the HashSet
, it changes its hash and thus can no longer be found by contains()
and remove()
.
Consider the following example:
public class Child {
private int id;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public Child(int id) {
this.id = id;
}
//other fields
@Override
public int hashCode() {
return id;
}
@Override
public boolean equals(Object obj) {
//instanceof checks for null, but whatever...
if (obj == null || !(obj instanceof Child)) {
return false;
}
return this.id == ((Child)obj).id;
}
}
In the following snipped, the HashSet
cannot remove the object because it cannot find it based on its new hash. Of course, it is not a bug, just one of the basic principles of a HashSet
(which uses a HashMap
internally).
public static void main(String[] args) {
Child child1 = new Child(123);
HashSet<Child> hashSet = new HashSet<>();
hashSet.add(child1); // puts to hash table at position X
child1.setId(321);
hashSet.remove(child1); // looks at position Y, finds nothing there
//child1 is still in the set
}
PS: Note that this answer is not a perfect match for the question as asked
(the class in question does not override hashCode
nor equals
). It is more an explanation which depicts the most probable cause for the need of the 'workaround' mentioned by @Mustafa-Kemal AND you have to keep this in mind even when using the widely used approach mentioned by @Vlad-Mihalcea.
Note 1: EntityManager::merge(...)
may change (and usually does) the memory-address of an object, used (not guaranteed for my part) for the default calculation of hashCode()
- see System.identityHashCode(Object x);
for more info.
Note 2: EntityManager::persist(...)
may change the property used for hashCode calcullation IF you use a custom hashCode method - yes, I am talking about the primary-key, an id, here which is quite tempting to use as hashCode :)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With