orphanRemoval=true does not work in bidirectional relationships (without cascading)
Description
Consider the following two entities with a bidirectional relationship between them:
@Entity @Table(name="product") public class Product { @Id @GeneratedValue(strategy=GenerationType.AUTO) private Long id;
@OneToMany(mappedBy = "product", orphanRemoval = true)//, cascade = {CascadeType.PERSIST} private List<Feature> features = new ArrayList<Feature>();
private String name;
}
@Entity @Table(name="feature") public class Feature {
@Id @GeneratedValue(strategy=GenerationType.AUTO) private Long id;
@ManyToOne() private Product product;
private String name; }
Now, clearing the collection of features in the Product will not result in deleting all Features of that product, as the JPA spec requires. The workaround is setting the CascadeType.PERSIST in the Product entity.
Test Case: entityManager.getTransaction().begin(); Product product = new Product(); List<Feature> features = new ArrayList<Feature>(); Feature newFeature = new Feature(product); newFeature.setName("Feature 1"); entityManager.persist(newFeature); features.add(newFeature); product.setFeatures(features); entityManager.persist(product); entityManager.flush(); entityManager.getTransaction().commit(); entityManager.clear();
//1. Changing product's features entityManager.getTransaction().begin(); Product productFound = entityManager.find(Product.class, product.getId()); log.info("found=" + productFound +" class "+productFound.getClass()); productFound.getFeatures().clear(); productFound.setName("Name changed");
Feature newFeature2 = new Feature(productFound); newFeature2.setName("Feature 2"); //entityManager.persist(newFeature2); //productFound.getFeatures().add(newFeature2); log.info("Product entity is managed: " + entityManager.contains(productFound));
Consider the following two entities with a bidirectional relationship between them:
@Entity
@Table(name="product")
public class Product {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
@OneToMany(mappedBy = "product", orphanRemoval = true)//, cascade = {CascadeType.PERSIST}
private List<Feature> features = new ArrayList<Feature>();
private String name;
}
@Entity
@Table(name="feature")
public class Feature {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
@ManyToOne()
private Product product;
private String name;
}
Now, clearing the collection of features in the Product will not result in deleting all Features of that product, as the JPA spec requires. The workaround is setting the CascadeType.PERSIST in the Product entity.
Test Case:
entityManager.getTransaction().begin();
Product product = new Product();
List<Feature> features = new ArrayList<Feature>();
Feature newFeature = new Feature(product);
newFeature.setName("Feature 1");
entityManager.persist(newFeature);
features.add(newFeature);
product.setFeatures(features);
entityManager.persist(product);
entityManager.flush();
entityManager.getTransaction().commit();
entityManager.clear();
//1. Changing product's features
entityManager.getTransaction().begin();
Product productFound = entityManager.find(Product.class, product.getId());
log.info("found=" + productFound +" class "+productFound.getClass());
productFound.getFeatures().clear();
productFound.setName("Name changed");
Feature newFeature2 = new Feature(productFound);
newFeature2.setName("Feature 2");
//entityManager.persist(newFeature2);
//productFound.getFeatures().add(newFeature2);
log.info("Product entity is managed: " + entityManager.contains(productFound));
log.info("Updating product");
entityManager.merge(productFound);
entityManager.getTransaction().commit();