1
votes

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
2
This might sound as a dumb remark, but did you try doing your persistence inside a transaction (i.e. start transaction, persist everything, commit transaction)?Shivan Dragon
No, I haven't. From what I see here, I would have to create Entity objects for each object I want to save, which would require some reworking of my current code, which tries to use the Event and Score objects themselves. If there are no other suggestions, I'll certainly give it a go.Bryan Herbst
You do know that you don't need "@Persistent" on all of those fields ? They will be persistent by default. Reading the persistence process log (at DEBUG level) would tell you why you have some errorDataNucleus
Yes, I am aware. However, the Defining Data Classes page's first tip suggests explicitly annotating all fields as persistent, as some are not persistent by default. I originally did not annotate them all, but decided to annotate them just in case that was the problem. I updated the end of my post with the log.Bryan Herbst

2 Answers

1
votes

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.

0
votes

Because I had encountered the same problem I had found this way of solving it.

I had used PersistenceManager to find all the persisted objects that I wanted to delete. And after this, I had tried to delete only the first one. Ex:

PersistenceManager pm = ...
List<MyEntity> myEntityList = pm.newQuery(MyEntity.class).executeList();
pm.deletePersistent(myEntityList.get(0));// Pretend that myEntityList has at least one object.

This way you will get another error that is going to tell you that is the problem. And from this second error, I had understood that I need, to remove the not null constraint on my foreign keys. Or starting from this point you should see MySql errors and not more JDO errors.