2
votes

Let's say I have a very easy, classic setup: GAE(1.7.4) + GWT(2.5.0) Application, running on local Jetty (Development Server), using JDO for persistence.

Let's also say I have just 2 @PersistenceCapable classes: Person and Color. Every Person has exactly one favourite Color, but it does not mean that this Person owns this Color - many different Persons can have the same favourite Color. There is a limited number of well-known Colors and a Color may exist even if it is not anyone's favourite.

To model this I should use @Unowned relationship - please correct me if I am wrong:

@PersistenceCapable
public class Color { // just the most regular Entity class

    @PrimaryKey
    @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
    private Key key;

    @Persistent
    String rgb;

    // getter, setter, no constructor
}

@PersistenceCapable
public class Person {

    @PrimaryKey
    @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
    private Key key;

    @Persistent
    String surname;

    @Persistent
    @Unowned // here is the tricky part
    Color color;

    // getters, setters, no constructor
}

With some simple, well-known, PersistentManager-based code, I am able to successfully create and persist an instance of a Color class. I see it in GAE Development Console -> Datastore Viewer, having nice generated Key and ID/Name of (13), and my assigned RGB.

With very similar code, I am able to create an instance of Person class (in another request), assign a pre-existing Color as his favourite color (it pre-existed, I obtained it by pm.getObjectById()) and persist it. I see it in Datastore Viewer, with my nice generated Key and ID/Name of (15) and my assigned surname, and color_key_OID of (13). This looks very promising.

But then, when I fetch the Person(15) back from the DB (simple pm.getObjectById(), no transactions), it has my assigned surname correctly, but has null instead of Color(13)! Right - the Datastore Viewer gets it ok, but my code does not.

Oh, the problematic code? "Person p = pm.getObjectById(Person.class, key);".

(side notes: I am also having the same problem with @Unowned collections (nice list of values in Datastore Viewer, but null Collection field in my code.) My JDO jars on classpath are "datanucleus-api-jdo-3.1.1.jar" and "jdo-api-3.0.1.jar" so I assume they support @Unowned. There is no problem with not-@Unowned fields. I get no exceptions upon persisting or fetching, just plain nulls as field values.)

4
datanucleus-api-jdo and jdo-api have nothing to do with Unowned. Unowned is a GAE-only concept. Obviously the JDO spec defines that it will only load what fields are in the fetch plan at the time and you don't present your code for how your fetching them and what lifecycle state they're in at that timeDataNucleus
Are you using gwt request factory or gwt rpc? If you are using request factory you can add the .with("color") to your request context and it will call getColor on the object. I used requestfactory specifically for this reason.Chris Hinshaw

4 Answers

3
votes

Either mark the color to be "eagerly fetched"

@Persistent(defaultFetchGroup="true")
@Unowned
Color color

or define your own fetchgroup like this:

@FetchGroup(name="eager", members={@Persistent(name="color")})
@PersistenceCapable
public class Person {

and use it if required by specifying the group to be fetched:

PersistenceManager pm = pmf.getPersistenceManager();
pm.getFetchPlan().addGroup("eager");
0
votes

I was facing the same issue in one of my @Unowned Lists. I had more other two, which the Array is fetched perfectly.

What solved this issue for me was to change the name of property for a bigger one. In your case is like change the property name from "color" to something bigger, like "myfavoritecolor".

0
votes

I have the same issue what you describe. How DataNucleus said you need to describe the whole lifecycle of the objects. In my case the problem was solved forcing getting the color, from the person object, before closing the PersistenceManager with the close() function.

Remember JDO uses the lazy-load technique to get objects.

0
votes

I was able to solve this problem by adding fetch groups to the query and not to persistent manager.

    PersistenceManager pm = PMF.get().getPersistenceManager();
    logger.info("EVENTS FETCH GROUPS : " + pm.getFetchPlan().getGroups());
    /*pm.getFetchPlan().addGroup("eventFetchGroup");
    pm.getFetchPlan().setMaxFetchDepth(2);*/
    Query q = pm.newQuery(Event.class);
    q.getFetchPlan().addGroup("eventFetchGroup");
    logger.info("EVENTS FETCH GROUPS : " +q.getFetchPlan().getGroups());
    q.setFilter("date >= fromDate && date <= toDate");
    q.declareParameters("java.util.Date fromDate, java.util.Date toDate");