Monday, June 15, 2009

Storing Data In App Engine

My students will have had a database course by now, so they'll be familiar with (or at least exposed to) SQL and relational database design.

The bad news is that App Engine doesn't support SQL and it isn't a relational database. Instead it supports an object oriented database and you use Java Data Objects to interact with it.

The good news is that this means you don't have to fool with a database design, you just write Java classes in a certain way, and App Engine takes care of the rest.

The bad news is that Java Data Objects use annotations, a Java feature you won't have seen yet. Annotations allow you to add features to a Java class without using inheritance.

The good news is that JDO does allow an SQL like syntax for querying, so that database course will come in handy (or maybe that's more bad news).

Enough of the good news/bad news bit. Let's dive into JDO.

An object that is stored into the database is called an entity. Entities have properties and a unique key (which can be autogenerated by App Engine, if you like). Oh, and we'll start to use the JDO terminology for database, which is datastore.

To specify a class as an entity, use the annotation @PersistenceCapable on the line before the class definition. For example, we'll need an entity to store information about a user (create this class in Eclipse in your project.server package):


@PersistenceCapable(identityType = IdentityType.APPLICATION)
public class User
{
}


That marks User as an entity that can be stored in the datastore. We also have to mark each field in User that we want stored in the datastore as @Persistent, and one of them as a @PrimaryKey.

I know that I'll need an autogenerated user id as a primary key (because the identifier returned by RPX is too long to be suitable as a primary key), and I'll need some other basic info. Here's what I came up with as a first pass:


@PersistenceCapable(identityType = IdentityType.APPLICATION)
public class User
{
  @PrimaryKey
  @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
  private Long id;
  
  @Persistent
  private String identifier;
  
  @Persistent
  private String name;
}


The valueStrategy argument on the id means it'll be automatically generated for me when I create new Users. Since the fields are private, I'll need public get methods for them, and set methods for the name and identifier. I won't show those here, but go ahead and add them to your version (this is a good time to figure out how to use Eclipse's Refactor->Encapsulate Field option to save yourself the typing).

To work with the datastore itself, we need an instance of PersistenceManagerFactory. The Google docs suggest using a singleton pattern for this, since the class is expensive to instantiate. Go ahead and use their PMF class as is in your project.server package.

In our RPXResults servlet, we'll need to use the identifier RPX provides to see if we already have the user in the datastore. If so, we'll load the existing data. Otherwise, we need to create the User instance and store it to the datastore.

We'll start in the next post with creating a new User and storing it to the datastore.

2 comments:

  1. I find Eclipse's Source->Generate Getters and Setters option more efficient than Refactor->Encapsulate Field option

    ReplyDelete
  2. Thanks for the alternative, Dan!

    ReplyDelete