DDD: Entity identity before being persisted

Dave New picture Dave New · Jan 21, 2014 · Viewed 8.1k times · Source

In Domain Driven Design, one of the defining characteristic of an Entity is that it has an identity.

Problem:

I am not able to provide a unique identity to Entities on instance creation. This identity is only provided by the repository once the entity is persisted (this value is provided from the underlying database).

I cannot begin to use Guid values at this point. The existing data is stored with int primary key values and I cannot generate a unique int on instantiation.

My solution:

  • Each Entity has an identity value
  • The identity is only set to a real identity once persisted (provided by the database)
  • The identity is set to default when instantiated before persistence
  • If the identity is default, entities are comparable through reference
  • If the identity is not default, entities are comparable through identity values

Code (the abstract base class for all entities):

public abstract class Entity<IdType>
{
    private readonly IdType uniqueId;

    public IdType Id
    {
        get 
        { 
            return uniqueId; 
        }
    }

    public Entity()
    {
        uniqueId = default(IdType);
    }

    public Entity(IdType id)
    {
        if (object.Equals(id, default(IdType)))
        {
            throw new ArgumentException("The Id of a Domain Model cannot be the default value");
        }

        uniqueId = id;
    }

    public override bool Equals(object obj)
    {
        if (uniqueId.Equals(default(IdType)))
        { 
            var entity = obj as Entity<IdType>;

            if (entity != null)
            {
                return uniqueId.Equals(entity.Id);
            }
        }

        return base.Equals(obj);
    }

    public override int GetHashCode()
    {
        return uniqueId.GetHashCode();
    }
}

Question:

  • Would you consider this to be a good alternative to generating Guid values on instance creation?
  • Are there better solutions out there for this problem?

Answer

nwang0 picture nwang0 · Jan 21, 2014

You can use a sequence generator to generate unique int/long identifiers when you instantiate an entity object.

The interface looks like:

interface SequenceGenerator {
    long getNextSequence();
}

A typical implementation of a sequence generator uses a sequence table in the database. The sequence table contains two columns: sequenceName and allocatedSequence.

When getNextSequence is called first time, it writes a large value (say 100) to the allocatedSequence column and return 1. The next call will return 2 without need to access the database. When the 100 sequences runs out, it reads and increments the allocatedSequence by 100 again.

Have a look at the SequenceHiLoGenerator in Hibernate source code. It basically does what I described above.