With Vaughn Vernon's Implementing Domain Driven Design samples in C# (https://github.com/VaughnVernon/IDDD_Samples) there is the identity type from which all classes dedicated for identity are built:
public class CalendarId : Identity
{
public CalendarId() { }
public CalendarId(string id)
: base(id)
{
}
}
Identity class:
public abstract class Identity : IEquatable<Identity>, IIdentity
{
public Identity()
{
this.Id = Guid.NewGuid().ToString();
}
public Identity(string id)
{
this.Id = id;
}
// currently for Entity Framework, set must be protected, not private.
// will be fixed in EF 6.
public string Id { get; protected set; }
public bool Equals(Identity id)
{
if (object.ReferenceEquals(this, id)) return true;
if (object.ReferenceEquals(null, id)) return false;
return this.Id.Equals(id.Id);
}
public override bool Equals(object anotherObject)
{
return Equals(anotherObject as Identity);
}
public override int GetHashCode()
{
return (this.GetType().GetHashCode() * 907) + this.Id.GetHashCode();
}
public override string ToString()
{
return this.GetType().Name + " [Id=" + Id + "]";
}
}
Identity interface:
public interface IIdentity
{
string Id { get; }
}
With a Calender class using the identity as so:
public class Calendar
{
public Calendar(Tenant tenant, CalendarId calendarId, string name, string description, Owner owner, IEnumerable<CalendarSharer> sharedWith = null)
{
// ... store passed parameters, including identity
this.id = id;
}
CalendarId calendarId;
public CalendarId CalendarId
{
get { return this.calendarId; }
}
}
What benefits does the above identity class provide over using say simpler types such as a GUID, or a string for the identity?
This comes down to design preference I guess.
Some time ago I did more-or-less the same thing. I had an
Identity<T>
concept since the key types could vary. MostlyGuid
but sometimesint
orstring
.I ended up abandoning the practice since it added more overhead than value and since my repositories always knew what type and key they were dealing with there was no real need to abstract it.
If, however, you find yourself with some generic bits that would, for instance, accept a repository and make the
Get
call for you then you may find it useful it. For example:But I have even used a more fine-grained, role-specific repository interface structure. I'll rather have this:
These can then be used by another repository interface:
But if you don't need that then a good entity specific repository interface will do:
Long story short: it doesn't buy you too much and I'd forgo it unless a real need arises.