Search code examples
javadaomongodb-javamorphia

MongoDB Auto-Incrementing id field with java mongo driver?


Whole day I have tried to find a answer on the question:

"How to add auto-Incrementing "id" field in an Entity class?".

I am using Morphia (a type-safe java library for Mongo DB). After a couple hours of digging in source code and googling I have found a LongIdEntity class in org.mongodb.morphia.utils package. Based on this class I have implemented the following solution. See below:

City class:

@Entity
public class City {

    @Id
    private Long id;
}

Hotel class:

@Entity
public class Hotel {

    @Id
    private Long id;
}

CityLongIdEntity class:

public class CityLongIdEntity extends LongIdEntity {

    public CityLongIdEntity(Datastore ds) {
        super(ds);
    }

}

HotelLongIdEntity class:

public class HotelLongIdEntity extends LongIdEntity {

    public HotelLongIdEntity(Datastore ds) {
        super(ds);
    }

}

DAO implementation:

CityDAO class:

public class CityDAO extends BasicDAO<City, Long> {

    public CityDAO(Datastore ds) {
        super(ds);
    }

    @Override
    public Key<City> save(City c) {

        if (c.getId() == null) {

            CityLongIdEntity ent = new CityLongIdEntity(getDs());
            getDs().save(ent);
            c.setId(ent.getMyLongId());
        }
        return getDs().save(c);
    }
}

HotelDAO class:

public class HotelDAO extends BasicDAO<Hotel, Long> {

    public HotelDAO(Datastore ds) {
        super(ds);
    }

    @Override
    public Key<Hotel> save(Hotel h) {

        if (h.getId() == null) {

            HotelLongIdEntity ent = new HotelLongIdEntity(getDs());
            getDs().save(ent);
            h.setId(ent.getMyLongId());
        }
        return getDs().save(h);
    }
}

Or you can see all this code on the Github

The UML diagram is also available: enter image description here

All this code works as expected and I am happy, but I have a couple questions:

  • As you can see, for each Entity I need to create additional Entity, for example: for entity City I created CityLongIdEntity (this entity is crucial part of auto-incrementing functionality) . In this case, if my app will have 20 Entities (City, Address, Hotel, User, Room, Order etc.) I will need to create a 40 classes! I am afraid, but I think it will be "Code smell". Am I right?
  • Also, the Entity doesn't know about EntityNameLongIdEntity and EntityNameLongIdEntity has no idea who is Entity. And only specific EntityDAO class combines ans uses those classes together. Is it ok? Or it is again code smell?
  • Each EntityDAO class overrides extends BasicDAO class and overrides method save(). The difference between overrided methods save() for different DAO classes is minimal. I am afraid. that is code duplication and code smell again. Am I right?

please provide your opinion.


Solution

  • We require numeric IDs on some entities, but our implementation is a little different:

    1. We use a regular ObjectId on all entities. Where required, we add a numeric ID.
    2. There is a dedicated AutoIncrementEntity, which keeps a counter for different keys — that would be your class name.
    3. We don't use DAOs but a generic save method, where we check if we have an instance of a class with a numeric ID. If that ID hasn't been set, we fetch one and update the AutoIncrementEntity. The relevant method isn't used at the moment — let me know if it's totally unclear and I'll finish that code.

    Two more things from my implementation, which might be a little confusing:

    • You can always provide a starting number, so our numeric IDs could be 1000, 1001, 1002,... instead of 1, 2, 3,...
    • The key in the AutoIncrementEntity isn't required to be a class, it could also be a subset. For example, you want to number employees within a company, then the key for employees of company A would be employee-A, for company B company-B,...