How do you make query results available after closing the persistence manager
Asked Answered
P

3

5

I am learning GAE and am getting a bit stuck. If I use the following, with a finally to make sure the persistence manager is closed, I get an exception when trying to actually read the Note objects:

public class Notes {
    public List<Note> getAll() {
    PersistenceManager pm = PMF.instance().getPersistenceManager();

    try {
        Query query = pm.newQuery("select from com.uptecs.google1.model.Note order by subject");
        return (List<Note>) query.execute();
    } finally {
        pm.close();
    }
    }
}

The exception I get is this:

Object Manager has been closed
org.datanucleus.exceptions.NucleusUserException: Object Manager has been closed
    at org.datanucleus.ObjectManagerImpl.assertIsOpen(ObjectManagerImpl.java:3876)
    at org.datanucleus.ObjectManagerImpl.getFetchPlan(ObjectManagerImpl.java:376)
    at org.datanucleus.store.query.Query.getFetchPlan(Query.java:497)
Paba answered 13/7, 2010 at 23:1 Comment(0)
B
9

Try detaching the object from the graph with detachable="true":

@PersistenceCapable(identityType = IdentityType.APPLICATION, detachable="true")
public class Note {
    @PrimaryKey
    @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
    private Long key;
...
}

Note: I totally understand the need for this, sometimes you need to retrieve the objects and lists in a controller, close the PM in the controller, then pass the models to the views. Until better solutions are known to me, this is what I am doing this on JDO/GAE with no problems so far.

List:

It seems to me that you will have to detach all the items in the list if you want to be able to use them after the PM is closed. I'd use this to get specific lists of items. A full getAll() can be very big in size.

public List<Note> getList(){
    List<Note> detachedList=null, list=null;
    try {
        String query = "select from " + Note.class.getName();
        pm = PMF.get().getPersistenceManager();
        list = (List<Note>)pm.newQuery(query).execute();            
        detachedList = new ArrayList<Note>();
        for(Note obj : list){
            detachedList.add(pm.detachCopy(obj));
        }

    } finally {
        pm.close();
    }
    return detachedList;

}

By Key:

public Note findByKey(Long key) {
    Note detachedCopy=null, object=null;
    try{
        pm= PMF.get().getPersistenceManager();
        object = pm.getObjectById(Note.class,key);
        detachedCopy = pm.detachCopy(object);
    }catch (JDOObjectNotFoundException e) {
        return null; // or whatever
    } 
    finally {
        pm.close(); // close here
    }
    return detachedCopy;

}

Afer the close, you have a detached copy, with which you can work.

Reference: http://www.datanucleus.org/products/accessplatform_1_1/jdo/attach_detach.html

Berezina answered 13/7, 2010 at 23:17 Comment(2)
I understand this part, the bit I dont understand is it is a list. Am I supposed to iterate through the whole list and detach each item?Paba
Yes, that's how I went about it. I couldn't get it to detach a list, when I try to do so I get a org.datanucleus.jdo.exceptions.ClassNotPersistenceCapableException: The class "The class "org.datanucleus.store.appengine.query.StreamingQueryResult" is not persistable. Seems this is what needs to be done if you want the individual items detached and close the PM.Berezina
R
1

When result is returned in the list - objects are retrieved lazily (only when you ask for them). Since your persistence manager is closed you get an exception. By "detaching" the objects your are effectively telling the persistence manager to retrieve them eagerly.

Rolypoly answered 13/7, 2010 at 23:50 Comment(0)
X
0

In addition to the answer from bakkal, I would say that you absolutely need the detachable="true" annotation parameter, otherwise you will never get it to work. To detach a list of objects, you can also use pm.detachCopyAll(your_query_result_list), wich will be a bit faster than your implementation of the iteration to detach, and will let you spare a few lines of code. Thanks JDO ! ;-) But be aware, this method requires explicit cast of its results.

Here's a working example I currently use in my last App (the Key used in the query is an Encoded String) :

pm = PMF.get().getPersistenceManager();

Query query = pm.newQuery(TandemSubscription.class);
query.setFilter("groupSubscriptionKey==groupSubscriptionKeyParam");
query.setOrdering("dateRDV desc");
query.declareParameters("String groupSubscriptionKeyParam");

// Get Data
@SuppressWarnings("unchecked")          
List<TandemSubscription> savedSubscriptions = 
     (List<TandemSubscription>) query.execute(Key);

// Detach all objects in the list
savedSubscriptions = 
     (List<TandemSubscription>) pm.detachCopyAll(savedSubscriptions);

pm.close();

// Now you can use the list and its content.

I Hope this helps a bit.

Xiomaraxiong answered 31/7, 2012 at 0:4 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.