I have an issue with the orphan removal in JPA 2. Inside a transaction I create the target object of one-to-one relation (OrderDirectDebit) then add it to an existing and persistent DonationIntent (using merge method). Then I remove the relation by nullifying it. Then I persist again (using merge method again).
I have orphanRemoval configured for the relation but still the object is not removed. The spec says that the remove operation is applied when flush operation is called ( which should occur as soon as the transaction ends). But in my example the orphaned entity is still there after commit. When I call flush manually after the merge operation (inside my custom persist method), the orphaned entity gets removed. If I call the flush operation manually on a different entity manager that uses the same persistence context (from an interceptor), the orphaned entity does not get removed.
I can't make any sense of the behaviour. Do I have to call to flush manually directly after the merge? Does that make any sense? Please comment. Here are my class definitions, the persist method of the repository and the unit test code:
// this is a method of a stateless bean with transaction required
// it is run inside an arquillian unit test
public void testOrderCreation() {
DonationIntent donation = repositoryDonationIntent.findById(id);
Country country = testhelper.getCountryGermany();
BankAccount bankAccount =testhelper.getBankAccountForTestPerson1();
Assert.assertFalse(donation.createOrderDirectDebit(23.0d, country, OrderType.EState.NEW, bankAccount).hasErrors());
donation = repositoryDonationIntent.persist(donation);
Assert.assertNotNull(donation.getOrder());
donation.setOrder(null);
donation = repositoryDonationIntent.persist(donation);
Assert.assertTrue(repositoryDonationIntent.findById(donation.getId()) == donation);
Assert.assertNull(repositoryDonationIntent.findById(donation.getId()).getOrder());
//the assert verifies the the relation of the object in the persistence context is null,still after commit it does not remove it
}
The entity model:
@Entity
public class DonationIntent extends AutoIdDomainObject implements IAggregateRoot<Long> {
@OneToOne(cascade = CascadeType.ALL, optional = true, orphanRemoval = true)
private OrderType order; // this is the relation that does not get orphaned
}
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
public abstract class OrderType extends AutoIdDomainObject {
// some more attributes and relations here
}
@Entity
public class OrderDirectDebit extends OrderType {
// some more attributes and relations here
}
The persist method of the repository:
@Override
public <D extends IDomainObject<?>> D persist(Class<D> domainClass, D domainObject) {
//TODO Do not permit old revisions of versioned objects to be persisted
if (domainObject == null)
return null;
// invalid domain objects may not be persisted
if (!domainObject.isValid()) {
DomainObjectErrorLogger.log(domainObject.getErrors());
return domainObject;
}
// check if update or insert
if (isPersistent(domainClass, domainObject)) {
domainObject = em.merge(domainObject);
em.flush(); // a call to flush here will remove orphaned entity
} else {
em.persist(domainObject);
}
return domainObject;
}