:-) 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.
