I have two classes, each of which are PersistentCapable- an Event and a Score class. The Event class contains an ArrayList of Scores.
I have a method that builds up a List of Events, then tries to save the Events and their corresponding Scores to the datastore using
PersistenceManager pm = PMF.get().getPersistenceManager();
try {
pm.makePersistentAll(Event.getEvents());
} finally {
pm.close();
}
The Events all save to the datastore fine (I can see them all at /_ah/admin). The Scores, however, do not save (at least most of them don't).
All of the scores from the first Event save, but non of the other Event's Scores do. All of the events have scores, and the lists are populated prior to trying to save to the datastore.
My call to makePersistentAll()
is also throwing javax.jdo.JDOUserException: One or more instances could not be made persistent
Finally, I can see in the datastore admin that though the Events are all being saved, their score value is a list of a bunch (~15) null values. All other values are correct. The Keys are all unique as well (though I am manually generating those).
Any ideas on what is going wrong?
Event:
@PersistenceCapable(detachable="true")
public class Event {
@NotPersistent
protected static ArrayList<Event> events = new ArrayList<Event>();
@PrimaryKey
@Persistent
private Key key;
@Persistent
private String name;
@Persistent
private String date;
@Persistent
private String year;
@Persistent
private String scoresUrl;
@Persistent
private ArrayList<Score> scores;
Score:
@PersistenceCapable(detachable="true")
public class Score {
@PrimaryKey
@Persistent
private Key key;
@Persistent
private Key eventKey;
@Persistent
private String unitName;
@Persistent
private int place;
@Persistent
private float score;
After setting .level = FINEST
in logging.properties, I see three entries that I think might be causing the problem just after all of the Events are saved. It appears as though the connection is being closed before the makePersistentAll()
can get down to the Score objects.
Aug 17, 2012 2:15:42 PM org.datanucleus.store.connection.ConnectionManagerImpl closeAllConnections
FINE: Connection found in the pool : com.google.appengine.datanucleus.DatastoreConnectionFactoryImpl$DatastoreManagedConnection@77a477b7 for key=org.datanucleus.ObjectManagerImpl@45e4d960 in factory=ConnectionFactory:nontx[com.google.appengine.datanucleus.DatastoreConnectionFactoryImpl@4eafccbe] but owner object closing so closing connection
Aug 17, 2012 2:15:42 PM org.datanucleus.store.connection.ConnectionManagerImpl$1 managedConnectionPostClose
FINE: Connection removed from the pool : com.google.appengine.datanucleus.DatastoreConnectionFactoryImpl$DatastoreManagedConnection@77a477b7 for key=org.datanucleus.ObjectManagerImpl@45e4d960 in factory=ConnectionFactory:nontx[com.google.appengine.datanucleus.DatastoreConnectionFactoryImpl@4eafccbe]
Aug 17, 2012 2:15:42 PM com.google.apphosting.utils.jetty.JettyLogger warn
WARNING: /scores
javax.jdo.JDOUserException: One or more instances could not be made persistent
As per Shivan Dragon's suggestion, I moved from using a PersistenceManager to doing everything within a transaction.
It doesn't look nearly as neat (because I need to explicitly set each property), but it now works as expected and no longer throws an Exception.
I'm decidedly okay with the extra clutter, as this method also gives me better control over when to and when not to save my data for individual Entities to the datastore.