Search code examples
javagoogle-app-engineentity-relationshipone-to-manyjdo

Using one-to-many owned relationship in JDO - AppEngine


I'm new to JDO and its concept. I worked with ORMLite before which is very simple, and I can't figure out how should I do in JDO what I did in ORMLite. I have 2 entities, Broadcast and Movie. Every Broadcast has one Movie and a Movie can have many Broadcastss. The id of a broadcast is not generated, it's configured before persisting it. So this is what I did:

@PersistenceCapable
public class Broadcast {

    @PrimaryKey
    private String id;

    @Persistent
    private Movie movie;

    //More fields....
}

Now this is the Movie class (again the id is not generated, it's configured before saving the object):

@PersistenceCapable
public class Movie {

    @PrimaryKey
    private String id;

    @Persistent(mappedBy = "movie")
    private List<Broadcast> broadcasts;

    //More fields....
}

Now, I have a servlet that is fetching and saving all the data in the DB. First, I fetch all the Broadcasts, for every Broadcast's movie all I know is the title, and its ID, so I save the Broadcast with a Movie object in it with a transaction (because there are two objects that are saved, so this must be atomic action):

// Check if this broadcast already exist.
try {
     mgr.getObjectById(Broadcast.class, brdcst.getId());
} catch (Exception e) {
     if(e instanceof JDOObjectNotFoundException){
    Transaction tx = null;
    try{
        tx = mgr.currentTransaction();
        tx.begin();
        mgr.makePersistent(brdcst);
        tx.commit();
    }
    catch(Exception e1){
        sLogger.log(Level.WARNING, e.getMessage());
    }
    finally{
        if (tx.isActive()) {
            tx.rollback();
        }
        mgr.flush();
    }

     }
     else sLogger.log(Level.WARNING, e.getMessage());
}

Then, I'm fetching the movie's data and saving it too, with the same ID, overriding the previous object (In other thread with no reference to the Broadcast object).

try {
    sLogger.log(Level.INFO, "Added the movie: " + movie);
    mgr.makePersistent(movie);
} catch (Exception e) {
    e.printStackTrace();
}
finally{
    mgr.flush();
}

So just to be clear, this is what happening in ORMLite and what I want to happen here. When I'm saving the Broadcast object I'm adding the movie with the ID to it, so in the future this ID will help him to get reference to its Movie in the database.

But whenever I'm querying the DB for broadcasts and hope to find references to movies in them all I get is null or this exception:

Field Broadcast.movie should be able to provide a reference to its parent but the entity does not have a parent.  Did you perhaps try to establish an instance of Broadcast as the child of an instance of Movie after the child had already been persisted?

So, what am I doing wrong here?


Solution

  • A bit explanation of what was going here: I had a List of Broadcasts fetched from the web. Every Broadcast in the list had a Movie object inside (Broadcast.setMovie), which only had a title. My purpose was to iterate over this list of broadcasts and fetch the needed information for every Broadcast's movie (this is why I used mgr.flush() in the end of every operation). So first I added the Broadcast to the datastore if it didn't exist, and then fetched the data for the movie and persisted it too. And there was my problem, in ORMLite, when you have a field which is foreign, and you store this object, the framework is saving this object and the id of the foreign field's object. So, let's say I had a Broadcast with id=10 and a Movie inside him with id=2, the framework would save the Broadcast to the database with 2 in the movie field. So this is what I wanted to do here but in JDO it's not working like this. After following the good example @Noofiz shared in his answer, I figured out I was doing it wrong and needed to do it in reverse order. Take the movie from every broadcast object, add the broadcast to the movie using Movie.addBroadcast and persist it in the datastore, and this is what I did, and it's working fine.

    So thanks everyone for your help and I hope this will help other people.