[ 
https://issues.apache.org/jira/browse/OPENJPA-722?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Xiaoqin Feng updated OPENJPA-722:
---------------------------------

    Attachment: openjpa-722-V2.patch

Yes, we shouldn't save PCState in pcDetachedState since pcDetachedStaet is used 
for loaded field, version info to make attach process more efficient.
V2 patch is attached.
Here is my solution:
1. Our assumption according to EntityManager.clear() API is 
""EntityManager.clear() will not flush new, dirty, removed entities in context 
but just detach all managed entities".

At first I thought we need to pass along flush=false from 
BrokerImpl.detachAll(OpCallbacks call, boolean flush) to DetachManager 
_flushBeforeDetach as openjpa-591 mentioned. Then I realized in 
BrokerImpl.detachAllInternal(), new DetachManager(this, true, call).detachAll 
(new ManagedObjectCollection(states)) actually pass in full=true so 
_flushBeforeDetach has no effect in this case and flush logic in DetachManager 
will be skipped. 

So I reverted my change in V1 patch for this part.

2. To make not flushed new entity to be inserted after merge, we don't save 
DetachedStateManager in detached object. When it merged back, exisitng openjpa 
framework could handle it correctly and add it to insert list.

3. To make not flushed dirty entity to be updated after merge, we save dirty 
flag BitSet when it is detached. 

4. As for removed entity, according to EJB3.0 persist spec 3.2.5,  remove call 
actually remove the entity from context, em.contains(obj) return false. It is 
not a managed entity and shouldn't be detached for EntityManager.clear() and 
not suppose to merge it back and be removed from DB in next commit/flush. User 
suppose to flush it before calling clear().
Note: 
Although I found openjpa may detach deleted-not-flushed entity as a side 
effect, we don't need to support merge scenario as I claimed above.

sm.isNew() && !sm.isDeleted() && !sm.isFlushed() in 
DetachManager.useDetachedStateManager() also make sure PNewDeletedState and 
PNewFlushedDeletedState will not be merged and take as a PNEW state and get 
inserted.


> persist - clear - merge scenario doesn't work
> ---------------------------------------------
>
>                 Key: OPENJPA-722
>                 URL: https://issues.apache.org/jira/browse/OPENJPA-722
>             Project: OpenJPA
>          Issue Type: Sub-task
>          Components: kernel
>    Affects Versions: 1.0.3, 1.1.0, 1.2.0
>            Reporter: Xiaoqin Feng
>            Assignee: Jeremy Bauer
>         Attachments: openjpa-722-fromQin.patch, openjpa-722-V2.patch, 
> TestEntityManagerClear-V2.java, TestEntityManagerClear.java
>
>
> EntityManager.clear() now don't  flush new object but only detach it.
> But DetachManager still flush dirty object and assume detached objects are in 
> clean state.
> When the "new" object is merged back and transaction commit,  because the 
> object state lost its original state PNEW, it will not be added to insert 
> list  and not flushed to DB.
> According to the EntityManager.clear() API,  changes made to entities that 
> have not been flushed to the database will not be persisted.  When they 
> merges back to persistent context, they all should kept there original state.
> I added the following test to 
> org.apache.openjpa.persistence.simple.TestEntityManagerClear.
>     public void testClearMerge() {
>         // Create EntityManager and Start a transaction (1)
>         begin();
>         // Insert a new object then clear persistent context
>         AllFieldTypes testObject1 = new AllFieldTypes();
>         testObject1.setStringField("my test object1");
>         persist(testObject1);
>         //Object1 is not flushed to DB but only detached by clear().
>         em.clear();
>         em.merge(testObject1);
>         //expect the PCState is same as before detached, 
>         //so it is PNew instead of PCLEAN and is add to insert list.
>         commit();
>         
>         //Start a new transaction
>         begin();
>         
>         // Attempt retrieve of Object1 from previous PC (should exist)
>         assertEquals(1, query("select x from AllFieldTypes x "
>             + "where x.stringField = 'my test object1'").
>                 getResultList().size());
>         
>         // Rollback the transaction and close everything
>         rollback();
>     }

-- 
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.

Reply via email to