C# Domain Model – Auto-Incremental ID in Domain Object

cdomain-driven-designdomain-modelidentity

I read a lot about auto-incremental id (guid, interlocked.increment, ObjectIdGenerator…) but don't find nothing for my situation.

In my domain model user ask to have an automatic progressive numeric Id for each Activity they create.

Since it's a user request I want to put it in my domain model, but the mode I usually do it in older application without good architecture ) is accessing database, retrieve the max and add 1; so I can't do it in my object since domain layer must not be aware of db.

Don't like db identity for lack of control (sometimes db administrator have to change the id for user error on creation of activity).

interlocked.increment look fine but my application is installed on every user machine so I can't use it

Since it must be intelligible and progressive I can't use guid

I find a good idea in Lev Gorodinski article about Service Domain in Domain-Driven-Design: define the interface of a GenerateActivityId in domain layer as a Domain Service, but I don't find a way to make a good implementation of it.

Any suggestion?

EDIT:
Lev Gorodinski idea:

public class Activity {
  public int Id {get; private set;}
  public string Description {get;set;}

  public Activity (string description){
    this.Description = description 
    this.Id = generator.GenerateId()
  }
}

public interface IIdGenerator{
  int GenerateId()
}

but i don't see where "generator" is defined and don't found IIdGenerator implementation: where should i put the implementation?
In ActivityRepository? If yes i can omit IIdGenerator for the IActiviryRepositoryInteface ?

Best Answer

Separate the user's need for some order number from the Primary Key/ID in the database. Make sure you identify why they want this numbering system and what they plan on doing with it.

If this represents the order they've entered their Activities, how do you handle a deletion? Do you leave a gap in the numbering? If order of entry is the driving force, save the date/time of entry and then you can create an order number / ID on the fly. This can even be a part of a select statement from a database using some type of Row_Number function if you don't want to do it in your app. They're very efficient, but you would have to perform this on all the records and then retrieve a subset of those records. If performance becomes a problem, you're going to have to save the values and then have some a ReOrdering function after a deletion.

If gaps in the numbering system are OK, then you can make this number permanant. To add a new number, you just need to query the database and get the last one. It's no different than retreiving any other value. DBs are pretty efficient at getting Max() values.

EDIT: I don't see any reason why this can't be generated in the database. It doesn't have to be the primary key just auto incremented. I know a DBA might change PK's if this app grows into some replicated environment or someone wants to put some intelligence in the number. The users need to understand by changing these numbers they run the risk of not being able to reference them the same way in their future meetings (Assuming someone keeps all the paper copies.).