Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
[eclipselink-users] Looks like Hibernate design bug about resurrecting deleted object contaminated JPA, so EclipseLink

Looks like Hibernate design bug about resurrecting deleted object
contaminated JPA, so EclipseLink.

I have a complex application that is originally based on
TopLink/EclipseLink native API. I mean by "complex" an application where
it is unrealistic to babysit every use case, or code path to put
workaround to fix thorny framework.

In native EclipseLink, the functionality of persistence by reachability
was simpler and likely the right thing. Any object that was reachable
was persisted. So if I had a chick and a roster having bidirectional
relationship I could just register any one of them and the other would
have been persisted.

Also if I would have deleted explicitly one of them without setting
existing reference to null, then in the next UOW I would have found null
in the reference pointing to the deleted animal, a reasonable default.

Now in JPA:

I use the hook in persistence.xml to use native EclipseLink mapping. The
mapping is imported but defaulting with no cascade of any kind. I then
fix the wrong default by setting cascade persist everywhere, and cascade
delete to all private owned relationships, matching the native behavior.

Then my complex application start to break with simple use case doing
deletion. I can simplify the broken use case to this:
1- Read X, X has one child having bidirectional relationship
2- Delete X EXPLICITLY
3- Commit

Then X is not deleted! My explicit wish have been overridden by some
weird implicit feature.

Remember, I have a complex application, not a lab test case used by some
specification writer. Now, if I babysit all my hundreds of references to
remove cascade persist from child to parent, existing code that was
working fine by just explicitly register the child will be broken.

EclipseLink one-to-many requires back reference to parent, so I have
been pushed to have more bidirectionality than what I wished for.

Also it's not always child to parent relationship that will trigger
resurrection. I likely have in my old application extra reference to the
deleted object that have not been nullified.

Maybe because Oracle is a big company, I was expecting they provide way
for backward compatibility. However, no flag exist to void the JPA
design bug.

You can see below that some Oracle developer agree that this design bug
is not the right thing:

Extract from
http://fisheye2.atlassian.com/browse/~raw,r=4388/eclipselink/trunk/found
ation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/
sessions/UnitOfWorkImpl.java:

public void discoverAndPersistUnregisteredNewObjects(Object object,
boolean cascadePersist, Map newObjects, Map unregisteredExistingObjects,
Map visitedObjects) {
        if (object == null) {
            return;
        }
        
        if (cascadePersist && isObjectDeleted(object)) {
            // It is deleted but reference by a cascade persist mapping,
spec seems to state it should be undeleted, but seems wrong.
            // TODO: Reconsider this.
            undeleteObject(object);
        }

Someone could think that I should be able to find a hook to override the
method discoverAndPersistUnregisteredNewObjects, but concrete class is
hardcoded in EntityManagerImpl.java:

public RepeatableWriteUnitOfWork getActivePersistenceContext(Object txn)
{
        // use local uow as it will be local to this EM and not on the
txn
        if (this.extendedPersistenceContext == null ||
!this.extendedPersistenceContext.isActive()) {
            this.extendedPersistenceContext = new
RepeatableWriteUnitOfWork(this.serverSession.acquireClientSession(connec
tionPolicy, properties), this.referenceMode);
 
this.extendedPersistenceContext.setResumeUnitOfWorkOnTransactionCompleti
on(!this.closeOnCommit);
 
this.extendedPersistenceContext.setShouldDiscoverNewObjects(this.persist
OnCommit);
 
this.extendedPersistenceContext.setFlushClearCache(this.flushClearCache)
;
 
this.extendedPersistenceContext.setShouldValidateExistence(this.shouldVa
lidateExistence);
 
this.extendedPersistenceContext.setShouldCascadeCloneToJoinedRelationshi
p(true);


Back to the top