objectuser.blog(brain)

objectuser.getBlog().contains(anything)

  • a place for thoughts, explanations, etc.

    this is just a place to write things out so I can make sure i understand them, keep track of them, and to use them again as links, etc.
  • Subscribe

  • Advertisements

17 Minute JDO!

Posted by objectuser on July 4, 2009

I joked about learning JDO in 17 minutes in this thread on the GAE/J google group.  It really didn’t take me long to understand enough to replace the use of JPA in my project with JDO, but that doesn’t mean I’d be comfortable in JDO in most other circumstances … just JDO in my project on GAE.

Still, I thought I’d share what I had to do to convert from JPA to JDO in my GAE project.

Replace Your Annotations

Classes

Instead of the @Entity annotation on your classes, you’ll want something like this:

@PersistenceCapable(identityType = IdentityType.APPLICATION, detachable = "true")

You can check the JDO documentation for the meaning of these.  I’ve not seen anyone use anything but APPLICATION identity type.  I have detachable = “true” on all my classes because this seems to make more sense in the context of the very limited transactional support of GAE (you need this if you plan to work with your object outside of a transaction and then persist changes).

Fields

Replace you @Id and @GeneratedValue attributes with something like this:

@PrimaryKey
@Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)

Other fields are easier in JDO.  They generally just get:

@Persistent

This replaces @Basic, @Enumerated, @OneToOne …  You do need to provide the same “back reference” annotation on owned bidirectional child fields.  So, where in JPA you had:

@OneToOne(mappedBy = "parentReference")

You’ll now need:

@Persistent(mappedBy = "parentReference")

Converting the annotations is the easiest part.  The conversion is a bit more intrusive in your DAOs.

Update Your DAOs

Queries

Find By ID

I like JPA queries much better than JDO queries.  But JDO is not that bad.  Finding by primary key is just about the same.  Where in JPA you had:

entityManager.find(Target.class, id);

In JDO you have:

persistenceManager.getObjectById(Target.class, id);

Find Related Item

I use a lot of collections of keys in my app so I can efficiently perform queries on relationships.  In JPA the query was really simple (where there is a many-to-many relationship between class Many and class ToMany and ToMany has a list of keys of manys):

Query q = entityManager.createQuery("select m from " + ToMany.class.getName() + " m where m.manys = ?1");
q.setParameter(1, manyId);
q.getResultList();

The same thing in JDO looks like this:

Query q = getPersistenceManager().newQuery(ToMany.class);
q.setFilter("manys.contains(manyParameter)");
q.declareParameters("Long manyParameter");
q.execute(manyId);

Looking at it here, that doesn’t look bad at all.  Probably just my SQL-ish brain that prefers the JPA form.

A couple of more notes on returning lists of objects.  The list returned by the JDO implementation is very limited.  In my case, I needed it to support the “contains” method and the returned collection doesn’t.  So I put the values into a list and returned that:

return new ArrayList<ToMany>((List<ToMany>) q.execute(manyId));

Detaching

JPA is again easier when dealing with entities that span transactions.  You don’t have to explicitly mark an entity as being detachable and don’t have to explicitly detach it.  In JDO you need that detachable = “true” annotation property (see above).  Then, in your DAO you need to do something like this:

Target t = persistenceManager.getObjectById(Target.class, id);
return persistenceManager.detachCopy(t);

If you don’t do this, when you go to update the object t, you’ll get cool exceptions about explicitly setting the primary key.  If you don’t ever need to persist updates to that object, then there’s no reason to worry about detaching.

Note that I don’t really understand this very well.  So you should read the docs in case I have something totally mixed up about this.  But it works for me.  Hopefully it’ll give you a starting point.

Lazy Loading

In GAE all JPA relationships are lazily loaded.  It’s my understanding that the fetchType isn’t supported at all.  So if you want to load child objects when you find a parent, you have to do silly stuff in your DAOs.  If, for example, you have a class One and a class ToMany, with One having an owned relationship to ToMany, you have to do stuff like this:

One one = entityManager.find(One.class, id);
if (one.getToManys() != null) {
  one.getToManys().size(); // fetch the collection
}
return one;

The JDO support for this is much better.  In your One class, simply use the following annotation:

@Persistent(defaultFetchGroup = "true")

With that, no weirdness necessary.  Oh yeah.

Update Your Spring Configuration

You may not be using Spring, but if so, you’ll need to change your Spring configuration to inject the PersistenceManagerFactory instance into you DAOs.

I explained how to do this in a previous post.

Advertisements

11 Responses to “17 Minute JDO!”

  1. Steve said

    Thanks! Great cross-over tutorial for GAE programmers.

  2. Erik Bengtson said

    to automatically detach all objects in JDO set this property to true in the PMF javax.jdo.option.DetachAllOnCommit

    query in JDO like SQL:

    pm.newQuery(“SELECT FROM ” + ToMany.class.getName() + ” WHERE manys.contains(:manyParameter)”).execute(manyId)

    • objectuser said

      Thanks, Erik, that’s a good addition.

      There’s an unanswered post in the google group about the performance implication of making everything detachable and always detaching.

      Do you happen to know the implications of doing that?

  3. Note said

    What if I have 2 parameters?? Can I query One-To-Many object using parent key as a condition on where clause?
    Like
    I want to select a child from child table(entity) like “select from child where parent.key = parentKey”.
    Let say that the children were saved by parent. When parent have a list of children.

    here is my query.
    Query q = getPersistenceManager().newQuery(Child.class);
    q.setFilter(“parent.contains(parentId)”);
    q.declareParameters(“Key parentId”);
    q.execute(parent.getId());

    here is an error I’ve got.
    org.datanucleus.exceptions.ClassNotResolvedException: Class Key for query has not been resolved. Check the query and any imports specification:
    javax.jdo.JDOException: Class Key for query has not been resolved. Check the query and any imports specification

    Did I do anything wrong?

  4. HK said

    Hi, can I use something similar to ‘like’ keyword in SQL? For example, SELECT EMPNAME FROM EMPLOYEE WHERE EMPNAME LIKE ‘JOHN%’

  5. lukasw44 said

    @OneToMany(cascade = CascadeType.ALL) in JPA == @Persistent(mappedBy = ” …. “) in JDO ???

    • objectuser said

      My JPA is rusty but I don’t think they’re the same at all. JPA cascade affects how operations on the parent affect the children, while JDO mappedBy tells the persistence framework how to structure a mapping in the datastore.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

 
%d bloggers like this: