:-)  Happy to help Andy.

I'm not sure what is triggering the commit of the new object since I don't
see you calling pm.makePersistent() anywhere.  How are you concluding that
the TextEntry is actually persisted?

Max
On Tue, Dec 1, 2009 at 12:25 PM, a stevko <[email protected]> wrote:

> WOW Max!
> You deserve a gold star for your insight, TY! TY! TY!
>
> I added a PM parameter to my lookup utility layer and the code suddenly
> works as desired.
> While I was using a static PMFactory, I didn't realize that calling get()
> would begin a new transaction context every time,
> It does makes sense given the platforms 1 txn per entity group constraint.
>
> What I don't understand is what triggered the commit of the new object. I
> would assume the commit would be triggered by the 2nd pm going out of scope
> but it was already out of scope when the parent object was passed back from
> the lookup method.
> --Andy
>
>
>
> On Tue, Dec 1, 2009 at 10:23 AM, Max Ross (Google) <
> [email protected] <maxr%[email protected]>> wrote:
>
>> My suspicion is that in the update case you are starting your txn with a
>> PersistenceManager, then using a different PersistenceManager to load the
>> TextEntry (diaryManager.getTextEntryById().  I can't be sure because you
>> haven't posted the code for diaryManager, but if it does the same thing as
>> lookupTextChapterById() and pmp.get() creates a new PersistenceManager, then
>> this is probably what is going on.  You're not seeing the updates when you
>> commit the txn because the txn is not associated with the PersistenceManager
>> that loaded the TextEntry.  I'd recommend using the same PersistenceManager
>> for all these operations.
>>
>> Hope this helps,
>> Max
>>
>>
>> On Sun, Nov 29, 2009 at 4:00 PM, Stevko <[email protected]> wrote:
>>
>>> I'm struggling with a JDO data loss situation.
>>> The code below will NEW a  TextEntry object and hook it into the
>>> object tree just fine.
>>> The copy DTO updates are performed without error/exception thrown but
>>> all updates are lost.
>>> The fields that are being lost are privateComment, byLine,
>>> shortContent, longContent, longContentSize.
>>>
>>> I've attached a DN transaction log at the bottom.
>>> The object state is marked as 'dirty' but the ObjectManager does not
>>> 'put' the new string values.
>>> According to the logs, for some unknown reason, the DB
>>> DatastorePersistenceHandler commits the "new"  object prior to the
>>> copy of the associated data from the action DTO into the persistent
>>> object.
>>>
>>> I've broken this up into two sequential transactions complete with
>>> isolated lookups but the data loss continues.
>>>
>>> //-------------------------------------
>>> // abridged code - error checking removed...
>>> //
>>> private final Provider<PersistenceManager> pmp;
>>> private PersistenceManager pm;
>>>
>>> @Override
>>> public SaveTextEntryResult execute(SaveTextEntry action,
>>>                ExecutionContext context) throws ActionException {
>>>
>>>        String entryId = action.getEntryId();
>>>        SaveTextEntryResult result;
>>>        try {
>>>                pm = pmp.get();
>>>                pm.currentTransaction().begin();
>>>
>>>                TextEntry entry;
>>>
>>>                // ----------
>>>                // is this new or update?
>>>                if (action.isNewEntry()) {
>>>
>>>                        // lookup the chapterid and verify accountid
>>>                        TextChapter chapter =
>>> diaryManager.lookupTextChapterById(action
>>>                                        .getChapterId());
>>>                        entry = new TextEntry(action.getTimestamp(),
>>> chapter,
>>>                                                action.getSourceType(),
>>> action.getSourceId());
>>>
>>>                } else {
>>>                        // look up the textentry id
>>>                        entry =
>>> diaryManager.lookupTextEntryById(action.getEntryId());
>>>                }
>>> //---->>> new object is flushed here <<<------
>>>                // copy fields from action to object
>>>                entry.setPrivateComment(action.isPrivateComment());
>>>                entry.setByLine(action.getByLine());
>>>                logger.info("SaveTextEntry() short content =" +
>>> action.getShortContent() );
>>>                entry.setShortContent(action.getShortContent());
>>>                logger.info("SaveTextEntry() long content =" +
>>> action.getLongContent
>>> () );
>>>                entry.setLongContent(action.getLongContent());
>>>
>>> //---->>> persist object updates are not flushed here  <<<------
>>>                pm.currentTransaction().commit();
>>>
>>>                result = new SaveTextEntryResult(true, entry.getId() );
>>>
>>>        } finally {
>>>
>>>                if (pm.currentTransaction().isActive()) {
>>>                        logger.severe("SaveTextEntry caught exception");
>>>                        result = new SaveTextEntryResult(false, "");
>>>                        pm.currentTransaction().rollback();
>>>                }
>>>        }
>>>
>>>        return result;
>>> }
>>> //------------
>>> // related method below
>>>        public TextChapter lookupTextChapterById(String id) {
>>>                pm = pmp.get();
>>>
>>>                TextChapter chapter = pm.getObjectById(TextChapter.class,
>>> id);
>>>
>>>                return (chapter);
>>>        }
>>>
>>> //----------------------------------------------------------------
>>> // Persistent object definition (bean methods removed)
>>>
>>> @PersistenceCapable(identityType = IdentityType.APPLICATION )
>>> @FetchGroup(  name="children", members={
>>>        @Persistent(name="commentEntrys"),
>>>        @Persistent(name="chapter")
>>> })
>>> public class TextEntry implements Entry, Serializable,
>>> Comparable<TextEntry> {
>>>
>>> @PrimaryKey
>>> @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
>>> @Extension(vendorName = "datanucleus", key = "gae.encoded-pk", value =
>>> "true")
>>> private String id;
>>>
>>> @Persistent
>>> private Long accountId = new Long(0);
>>>
>>> // Parent collection with ArrayList<TextEntry>
>>> @Persistent
>>> private TextChapter chapter;
>>>
>>> @Persistent
>>> private Long timestamp = new Long(0);
>>>
>>> @Persistent
>>> private boolean privateComment = false;
>>>
>>> @Persistent
>>> private String byLine = "";
>>>
>>> @Persistent(defaultFetchGroup="true")
>>> private SourceType source = SourceType.UNKOWN;
>>>
>>> @Persistent
>>> private String sourceId = "";
>>>
>>> @Persistent(defaultFetchGroup="true")
>>> private String shortContent = null;
>>>
>>> @Persistent(defaultFetchGroup="true")
>>> private String longContentString = null;
>>>
>>> @Persistent(defaultFetchGroup="true")
>>> private Long longContentSize = new Long(-1);
>>>
>>> @Persistent(mappedBy = "textEntry")
>>> @Order(column="TEXTENTRY_COMMENTENTRY_IDX")
>>> private TreeSet< CommentEntry> commentEntrys = new TreeSet<
>>> CommentEntry>();
>>>
>>> public TextEntry(Long timestamp, TextChapter chapter,  SourceType
>>> source,
>>>                String sourceId) {
>>>        this.timestamp = timestamp;
>>>        this.source = source;
>>>        this.sourceId = sourceId;
>>>
>>>        // setup external references
>>>        this.chapter = chapter;
>>>        this.accountId = chapter.getAccountId();
>>>        chapter.add(this);
>>> }
>>>
>>>
>>> //-------------------------------------------------------------------------------------------------------
>>> // this is a log showing the point where the
>>> DatastorePersistenceHandler commits the fields.
>>>
>>> Nov 29, 2009 9:45:58 PM org.datanucleus.ObjectManagerImpl
>>> persistObjectInternal
>>> FINE: Making object persistent :
>>> "com.ninuku.diary2.server.diary.texten...@13c7edf"
>>> Nov 29, 2009 9:45:58 PM
>>> org.datanucleus.store.appengine.DatastorePersistenceHandler put
>>> FINE: Putting entity of kind TextEntry with key Diary(4)/TextChapter
>>> (7)/TextEntry(no-id-yet)
>>> Nov 29, 2009 9:45:58 PM
>>> org.datanucleus.store.appengine.DatastorePersistenceHandler put
>>> FINE:   timestamp : 1259531142320
>>> Nov 29, 2009 9:45:58 PM
>>> org.datanucleus.store.appengine.DatastorePersistenceHandler put
>>> FINE:   TEXTCHAPTER_TEXTENTRY_IDX : 7
>>> Nov 29, 2009 9:45:58 PM
>>> org.datanucleus.store.appengine.DatastorePersistenceHandler put
>>> FINE:   accountId : 2
>>> Nov 29, 2009 9:45:58 PM
>>> org.datanucleus.store.appengine.DatastorePersistenceHandler put
>>> FINE:   shortContent : null
>>> Nov 29, 2009 9:45:58 PM
>>> org.datanucleus.store.appengine.DatastorePersistenceHandler put
>>> FINE:   source : USER_MANUAL
>>> Nov 29, 2009 9:45:58 PM
>>> org.datanucleus.store.appengine.DatastorePersistenceHandler put
>>> FINE:   longContentSize : -1
>>> Nov 29, 2009 9:45:58 PM
>>> org.datanucleus.store.appengine.DatastorePersistenceHandler put
>>> FINE:   privateComment : false
>>> Nov 29, 2009 9:45:58 PM
>>> org.datanucleus.store.appengine.DatastorePersistenceHandler put
>>> FINE:   byLine :
>>> Nov 29, 2009 9:45:58 PM
>>> org.datanucleus.store.appengine.DatastorePersistenceHandler put
>>> FINE:   longContentString : null
>>> Nov 29, 2009 9:45:58 PM
>>> org.datanucleus.store.appengine.DatastorePersistenceHandler put
>>> FINE:   sourceId : 1259531142320
>>> Nov 29, 2009 9:45:58 PM org.datanucleus.sco.backed.TreeSet <init>
>>> FINE: Object "com.ninuku.diary2.server.diary.texten...@13c7edf" field
>>> "commentEntrys" is replaced by a SCO wrapper of type
>>> "org.datanucleus.sco.backed.TreeSet" [cache-values=true, lazy-
>>> loading=true, queued-operations=false, allow-nulls=false]
>>> Nov 29, 2009 9:45:59 PM
>>> org.datanucleus.store.appengine.DatastorePersistenceHandler get
>>> FINE: Getting entity of kind Diary with key Diary(4)
>>> Nov 29, 2009 9:46:22 PM
>>> com.google.appengine.api.datastore.dev.LocalDatastoreService
>>> $PersistDatastore persist
>>> INFO: Time to persist datastore: 10 ms
>>> Nov 29, 2009 9:46:32 PM
>>> com.ninuku.diary2.server.handler.SaveTextEntryHandler execute
>>> INFO: SaveTextEntry() short content =this is a short content update
>>> Nov 29, 2009 9:46:37 PM
>>> com.ninuku.diary2.server.handler.SaveTextEntryHandler execute
>>> INFO: SaveTextEntry() long content =this is a long content update
>>> Nov 29, 2009 9:46:40 PM org.datanucleus.TransactionImpl
>>> internalPreCommit
>>> FINE: Transaction committing for ObjectManager
>>> org.datanucleus.objectmanageri...@beef49
>>> Nov 29, 2009 9:46:40 PM org.datanucleus.ObjectManagerImpl
>>> flushInternal
>>> FINE: ObjectManager internalFlush() process started - 0 dirty objects
>>> Nov 29, 2009 9:46:40 PM org.datanucleus.ObjectManagerImpl
>>> flushInternal
>>> FINE: ObjectManager internalFlush() process finished
>>> Nov 29, 2009 9:46:40 PM org.datanucleus.transaction.Transaction commit
>>> FINE: Committing [DataNucleus Transaction, ID=Xid=
>>> //-----------------------------------------------------------------
>>> // this is the entry object debugger showing the dirty fields...
>>> this    SaveTextEntryHandler  (id=151)
>>> action  SaveTextEntry  (id=169)
>>> context AbstractDispatch$DefaultExecutionContext  (id=171)
>>> entryId
>>> "agxuaW51a3UtYWxwaGFyKwsSBURpYXJ5GAQMCxILVGV4dENoYXB0ZXIYBwwLEglUZXh0RW50cnkYFQw"
>>> (id=172)
>>> entry   TextEntry  (id=160)
>>>        accountId       Long  (id=174)
>>>        byLine  "" (id=177)
>>>        chapter TextChapter  (id=178)
>>>        commentEntrys   TreeSet  (id=181)
>>>
>>> id
>>>  
>>> "agxuaW51a3UtYWxwaGFyKwsSBURpYXJ5GAQMCxILVGV4dENoYXB0ZXIYBwwLEglUZXh0RW50cnkYFQw"
>>> (id=183)
>>>        jdoFlags        1
>>>        jdoStateManager JDOStateManagerImpl  (id=188)
>>>                objectValGenerators     null
>>>                activity        ActivityState  (id=205)
>>>                associatedValuesMap     HashMap<K,V>  (id=207)
>>>                changingState   false
>>>                cmd     ClassMetaData  (id=211)
>>>                currFM  null
>>>                currFMmonitor   Object  (id=213)
>>>                dirty   true
>>>                dirtyFields      (id=216)
>>>                        [0]     false
>>>                        [1]     false
>>>                        [2]     false
>>>                        [3]     false
>>>                        [4]     false
>>>                        [5]     true
>>>                        [6]     true
>>>                        [7]     true
>>>                        [8]     true
>>>                        [9]     false
>>>                        [10]    false
>>>                        [11]    false
>>>                embeddedOwners  null
>>>                fieldsToBeUpdatedAfterObjectInsertion   null
>>>                flushedNew      false
>>>                insertionNotifyList     null
>>>                jdoDfgFlags     1
>>>                loadedFields     (id=218)
>>>                loadingFieldsInFetchPlan        false
>>>                myFP    FetchPlan$FetchPlanForClass  (id=219)
>>>                myID    StringIdentity  (id=221)
>>>                myInternalID    null
>>>                myLC    PersistentNontransactionalDirty  (id=224)
>>>                myOM    ObjectManagerImpl  (id=227)
>>>                myPC    TextEntry  (id=160)
>>>                myVersion       null
>>>                operationalFlags        0
>>>                pcObjectType    0
>>>                postLoadPending false
>>>                preDeleteLoadedFields   null
>>>                referencedPC    null
>>>                relationManager null
>>>                restoreValues   false
>>>                savedFlags      1
>>>                savedImage      TextEntry  (id=231)
>>>                savedLoadedFields        (id=232)
>>>                storingPC       false
>>>                transactionalVersion    null
>>>                updatingForPostInsert   false
>>>        longContentSize Long  (id=192)
>>>        longContentString       "this is a long content update" (id=173)
>>>        privateComment  true
>>>        shortContent    "this is a short content update" (id=168)
>>>        source  SourceType  (id=200)
>>>        sourceId        "1259536113144" (id=203)
>>>        timestamp       Long  (id=204)
>>>
>>> --
>>>
>>> You received this message because you are subscribed to the Google Groups
>>> "Google App Engine for Java" group.
>>> To post to this group, send email to
>>> [email protected].
>>> To unsubscribe from this group, send email to
>>> [email protected]<google-appengine-java%[email protected]>
>>> .
>>> For more options, visit this group at
>>> http://groups.google.com/group/google-appengine-java?hl=en.
>>>
>>>
>>>
>>  --
>> You received this message because you are subscribed to the Google Groups
>> "Google App Engine for Java" group.
>> To post to this group, send email to
>> [email protected].
>> To unsubscribe from this group, send email to
>> [email protected]<google-appengine-java%[email protected]>
>> .
>> For more options, visit this group at
>> http://groups.google.com/group/google-appengine-java?hl=en.
>>
>
>  --
> You received this message because you are subscribed to the Google Groups
> "Google App Engine for Java" group.
> To post to this group, send email to
> [email protected].
> To unsubscribe from this group, send email to
> [email protected]<google-appengine-java%[email protected]>
> .
> For more options, visit this group at
> http://groups.google.com/group/google-appengine-java?hl=en.
>

--

You received this message because you are subscribed to the Google Groups 
"Google App Engine for Java" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/google-appengine-java?hl=en.


Reply via email to