JPA clear collection and add new items
This really seems to be a bug in many versions of Hibernate. I have tested it with EclipseLink and it works there without problem.
As workaround in Hibernate (tested in Hibernate 4.3.6-Final): Remove any cascading in the Feature
entity and add CascadeType.PERSIST
(or CascadeType.ALL
) in the Product
entity.
Just to make sure that it does not work, try the following:
EntityManager em = ...//fetch the entitymanager. If a Container-managed transaction, you already got it injected
em.getTransaction().begin();//only if resource-local persistence unit. Otherwise if JTA: open the transaction the JTA-specific way (if that was not already done by the container)
Product product = em.find(Product.class, productId);
for (Feature crtFeature : product.getFeatures()) {
if (!em.contains(crtFeature)) {
throw new RuntimeException("Feature is not managed, so removeOrpahns cannot work");
}
}
product.getFeatures().clear();
Feature feature = new Feature(product, ls);
em.persist(feature);//you need this, as there is no cascading from Product to Feature.
product.getFeatures().add(feature);
em.getTransaction().commit();//if you work with a resource-local persistence unit. Otherwise if JTA: commit the transaction the JTA-specific way (if that was not already done by the container)
Turns out that the actual solution was using a @JoinColumn annotation instead of the mappedBy="" parameter.
You try to clear only one side of the bidirectional association.
So instead of:
collection.clear();
Try clearing both sides and it should work:
for(Iterator<Feature> featureIterator = features.iterator();
featureIterator.hasNext(); ) {
Feature feature = featureIterator .next();
feature.setProduct(null);
featureIterator.remove();
}
Also, remove the cascade from @ManyToOne
and move it to @OneToMany
.
Mind the unique constraints
However, if you have a unique constraint, this clear + add
Anti-Pattern will not work since the INSERT action is executed before the DELETE one.
The proper way to do it is to check which entries need to be removed and just remove those. Then, add the new ones, and update the ones that got modified. This is how you do a collection merge properly.