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:
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:
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.