The Ironism

The Ironism


The lair of Lars J. Nilsson. Contains random musings on beer, writing and this thing we call life.

September 2012
MTWTFSS
« Aug Nov »
 12
3456789
10111213141516
17181920212223
24252627282930

Categories


Auto generated ID with Morphia and MongoDB

fungrimfungrim

Here’s a short how-to (with sources for the lazy) for using automatically generated integer ID with Morphia.

The problem is this:

MongoDB only accepts one ID type for a document, and that is the ObjectId. While this is no doubt fine for MongoDB, as Java developers it stings a bit. So here’s what we need to do:

So let’s dive in shall we. First, let’s create an entity:
[code lang=”java”]@Entity
public class User {

@Id
private Long id;

public User(Long id) {
this.id = id;
}

public User() { }

[…]
}[/code]
Beware: If you’re new to Morphia, watch out, these annotations are not JPA as you would expect, they are Morphia annotations.

Now, this won’t work as MongoDB will complain about the ID type. But before we solve it, let’s create a simple DAO shall we?
[code lang=”java”]public class UserDao {

    private Datastore store;

    public UserDao(Datastore store) {
        this.store = store;
    }

    public User get(Long id) {
        return store.get(User.class, id);
    }

    public User save(User u) {
        store.save(u);
        return u;
    }
}[/code]
This still won’t work as we haven’t solved the ID problem. In order to do that, we’ll first create a new document type, which we’ll use to store ID counters per entity we want to use (because you do want more than one entity don’t you?).
[code lang=”java”]@Entity
public class EntityId {

    @Id
    private String className;

// this is the actual ID counter, will
// be incremented atomically
    private Long counter = 1L;

    public EntityId() { }

    public EntityId(String className) {
        this.className = className;
    }

    […]
}[/code]
The EntityId will store a counter for each entity collection we use. So the “User” type will have one EntityId document in the database, and the counter will be atomically updated when we create new users. So when the entity is saved, if it doesn’t have an ID, create one (in the DAO):
[code lang=”java”]public User save(User u) {
    if(u.getId() == null) {
     Long id = generateId(u);
        u.setId(id);
    }
    store.save(u);
    return u;
}

// — PROTECTED METHODS — //

protected Long generateId(User entity) {
// lookup the collection name for the entity
String collName = store.getCollection(getClass()).getName();
// find any existing counters for the type
    Query<EntityId> q = store.find(EntityId.class, "_id", collName);
// create an update operation which increments the counter
    UpdateOperations<EntityId> update = store.createUpdateOperations(EntityId.class).inc("counter");
// execute on server, if not found null is return,
// else the counter is incremented atomically
    EntityId counter = store.findAndModify(q, update);
    if (counter == null) {
// so just create one
        counter = new EntityId(collName);
        store.save(counter);
    }
// return new id
    return counter.getCounter();
}[/code]
And that is, as they say, it. If you’ve read my friend Fredriks excellent post on how to unit test Morphia just go ahead and test it. Or if you’re lazy, download my sources, which contains a ready-made unit test and are mavenized, and spin it yourself.

Next time I’ll extend this little experiment to custom data type converters as well. Stay tuned!

The proprietor of this blog. Lunchtime poet, former opera singer, computer programmer. But not always in that order. Ask me again tomorrow.

    Comments 0
    There are currently no comments.