Entity Base Class

By Vladimir Khorikov

If you follow DDD principles, you eventually end up creating a base class for all the domain entities. It’s a good idea as it allows you to gather common logic in one place. When you decide to do that, you inevitably face the question what exactly should be included in that base entity and how it should be presented.

Interface as a base entity

I often see developers using interfaces as a base entity. Their code might look like this:

public interface IEntity

{

    int Id { get; }

}

While this approach guarantees that all domain entities have some minimum functionality (Id property in this example), in most cases having an interface as a base entity is a bad idea.

First of all, interfaces don’t allow you to gather any logic in them, you need to implement this logic yourself which leads to a massive code duplication. Even in the example above you need to create the Id property in every single entity, which itself is a heavy violation of the DRY principle.

Secondly, using an interface doesn’t show the appropriate relationship between the domain entities. When a class implements an interface it makes a promise about some functionality, and that’s it. Two classes implementing the same interface don’t give any promises about their relationship, they can belong to entirely unconnected hierarchies. In other words, IEntity interface introduces a “can do” relation (according to Bertrand Meyer’s classification), whereas domain entities should be connected to the base entity by “is a” relation. Every domain class not only has the Id property, but itself is an entity. It is important to remove possible misunderstandings, using an interface instead of the base class can lead to one.

How you shouldn’t implement base classes

Okay, but what logic do we need in the base domain class?
Obviously, it should have an Id field, which is mapped to a table’s primary key. All tables in the database must have ids with the same type so we could factor the Id property out to the base class. Here is how you should not do it:

public class Entity<T>

{

    public T Id { get; protected set; }

}

Motivation for such code it pretty clear: you have a base class that can be reused across multiple projects. For instance, if there is a web application with GUID Id columns in the database and a desktop app with integer Ids, it might seem a good idea to have the same class for both of them. In fact, this approach introduces accidental complexity because of premature generalization. There is no need in using a single base entity class for more than one project or bounded context. Each domain has its unique path, so let it grow independently. Just copy and paste the base entity class to a new project and specify the exact type that will be used for the Id property.

There’s a case I want to mention, though. Although you should create tables with primary keys of the same type only, you may have a legacy application, created by different developers, where they have database tables with primary keys of different types. Or there might be composite primary keys. In these cases, there is no way to inherit your domain classes from the same base class. The best solution here might be refactoring your database, although you should consider pros and cons of such decision. For a new project, you should always create database tables with a single Id column of the same type.

Entity base class: the code

So, what should the base domain class look like? Here is the code I use in production, let’s step through it.

public abstract class Entity

{

    public virtual long Id { get; protected set; }

 

    public override bool Equals(object obj)

    {

        var compareTo = obj as Entity;

 

        if (ReferenceEquals(compareTo, null))

            return false;

 

        if (ReferenceEquals(this, compareTo))

            return true;

 

        if (GetRealType() != compareTo.GetRealType())

            return false;

 

        if (!IsTransient() && !compareTo.IsTransient() && Id == compareTo.Id)

            return true;

 

        return false;

    }

 

    public static bool operator ==(Entity a, Entity b)

    {

        if (ReferenceEquals(a, null) && ReferenceEquals(b, null))

            return true;

 

        if (ReferenceEquals(a, null) || ReferenceEquals(b, null))

            return false;

 

        return a.Equals(b);

    }

 

    public static bool operator !=(Entity a, Entity b)

    {

        return !(a == b);

    }

 

    public override int GetHashCode()

    {

        return (GetRealType().ToString() + Id).GetHashCode();

    }

 

    public virtual bool IsTransient()

    {

        return Id == 0;

    }

 

    public virtual Type GetRealType()

    {

        return NHibernateUtil.GetClass(this);

    }

}

By default the Id property is of long type, which excludes the possibility of sequence exhausting. Also, all members are made virtual, because I use NHibernate where virtual members are required to create runtime proxies. Setter is made protected and not private because of NHibernate as well.

The most interesting part is equality members, which is generally the rest part of the class. To go further, we should step back and recall what it means to be equal.

There are three types of equality in enterprise software:

  • Reference equality means that two references refer to the same object in memory.
  • Identifier equality means that two different objects in memory refer to the same row in the database.
  • Logical equality means that two different objects and two different rows in the database are actually equal. It might happen when an object doesn’t have its own identity (such objects called value objects), and thus we can treat two different objects with identical fields as logically equal.

The Entity class covers the first two situations: when two objects either equal by reference or by identifier. Logical equality pertains to Value Objects I will cover later. Note, that GetRealType method is called in order to get the type of the objects. GetRealType() was added to the base class because NHibernate returns runtime proxy class type if you just call GetType() on an object, so we must call NHibernateUtil.GetClass() to get the underlying object type.

The second “if” statement in Equals method checks reference equality and the last one checks identifier equality. IsTransient method refers to the notion of objects’ states. They can be either saved in DB (this state is called persistent) or not saved (this state is called transient). It doesn’t matter why an object can be not saved: either because it was deleted or because insert wasn’t done in DB yet, this state is called transient regardless of the reason.

We must check the objects’ state because transient objects have Id property set to zero by default. We cannot check identifier equality if one of the objects doesn’t have the identifier yet. But if you assign the id by yourself, using non-native id generation strategy in NHibernate, then you can skip this.

GetHashCode method must be overridden together with the Equals method as well. They always come together because of the internal .NET logic. This logic can be illustrated in the code below. When you call Contains() method it loops through the objects in the list and calls GetHashCode() on each object. If the codes coincide it also calls Equal(). And only if the both checks, GetHashCode and Equal, are passed two objects considered as equal.

Entity obj = GetObjectSomehow();

List<Entity> objects = GetObjectsSomehow();

objects.Contains(obj);

It is a good idea to declare == and != operators as well, because by default == operator checks reference equality only.

Summary

I use this code in most of my projects, sometimes adding some functionality if it appears in all project’s domain classes. Such functionality might be version property (byte[] or int) or any other useful stuff. But don’t be carried away by this, add functionality to the base domain class if it belongs to all domain classes only. Otherwise, you may end up building God Object instead of a thin base entity.





  • GSerjo

    Nice article. Why you didn’t implement IEquatable on Enity?

    • http://enterprisecraftsmanship.com/ Vladimir Khorikov

      Thanks!
      IEquatable doesn’t provide any additional value here. The main use case for this interface is structs: it allows you to avoid unnecessary boxing/unboxing operations. Reference types can just use basic Equals(object) method.

  • Marcos Antonio

    Good article!!

    About your base class implementation, where the Entity class should reside? In my case, this class is inside the namespace MyApp.Domain (this is a class library) and according to DDD, the domain can’t reference any kind of technology or framework.

    My main doubt is because of this code:

    public virtual Type GetRealType()

    {

    return NHibernateUtil.GetClass(this);

    }

    There is a reference to NHibernate. Is that corret?

    Where is the correct place to put that base class?

    • http://enterprisecraftsmanship.com/ Vladimir Khorikov

      Excellent question!

      Indeed, the domain classes should be as decoupled from any ORM (or other technology) as possible, this principle is called Persistence Ignorance. Nevertheless, it is not always possible to completely remove ORM’s artifacts from your code. For example, if you use NHibernate, you need to mark all non-private class members as virtual. Another example: in Entity Framework, you can’t use private fields or properties in order to map them to database columns.

      There should be a balance here. Domain entities should be as persistent ignorant as possible, but at the same time, you aren’t be able to ignore your ORM completely, you need to conform to it at least at some point.

      GetRealType() is one of such trade-offs. I occasionally use it to find out the real type of the proxies that NHibernate generates, and it seems that the base Entity class is a good place to keep this logic. Entity class itself resides in MyApp.Domain assembly with the other domain classes.

      One point here: I advocate you follow YAGNI principle so add the GetRealType method to your base class only if you really use it. If not, don’t add it, you will always be able to add it later.

      Thank you for your comment!

  • Milad EP

    Hi,
    Thank you for your sharing,

    But I think it is impossible that use a non-generic class for all of the entities, because sometimes we need to use big-int,guid and the other types as primary keys and it will limit us to use this class as base class.
    The bast way I think to use a Generic with the Implementation of your class with inheriting an interface like IEntity for allowing user to re-use the base class in the other places.
    According to GetRealType and using Nhibernate.GetRealClass, I think it is a bad practice and we have to use an abstract method in this way and let the user to redefine a base class that inherited from your base class, in this way we’ve saved our base class from ORMs and we’ll able to re-use the base class for the other ORMs like EF in the current solution.

    What is your opinion?!

    • http://enterprisecraftsmanship.com/ Vladimir Khorikov

      Hi Milad, thanks for your comment.

      I personally think that programmers should try to be consistent with entities’ Ids within a single bounded context. I would consider having different types of primary keys a bad practice in this case. Note that you don’t have to be consistent across all bounded contexts in your domain model, it’s fine to have a BC with entities’ identifiers of the int type and another BC with GUIDs. In this case, I would create 2 different base entity classes, one for each BC.

      Regarding GetRealType – this is indeed an ORM abstraction leaking into the domain model. Trying to create as pure domain model as possible, we have to be pragmatic, though, and I would say that this “dirty” piece of code is justified in this particular case. However, the alternative you propose is nice and would work if you want to completely unbind the Entity class from the ORM concerns.

      To summarize:
      – I don’t recommend introducing an IEntity interface or an Entity base class.
      – Your alternative for the GetRealType method looks good.

      Hope that helps.

      • Milad EP

        Hi Vladimir,

        Could you please let me know your opinion about don’t using Generic classes as base class?
        What is the problem if we are using a BC as generic and what may be happens there?!

        If it s possible for you that provide me some references or short response about this topic, I’ll be thankful.

        Regards,

        • http://enterprisecraftsmanship.com/ Vladimir Khorikov

          Hi Milad,

          The main advantage I see in having a unified identifier type across the whole bounded context is simplicity. It’s easier to use a single common denominator for that purpose and not bother with multiple types of Ids. Of course, you can have a generic entity class to handle all possible identifier types, but to me, that’s an unnecessary over-complication.

          There’s no hard rule here, though, and I don’t see problems with the generic Entity base class other than what I just mentioned.

  • Subhash

    Hi,
    As C# does not support multiple inheritance, What if I have to inherit the class with other base class like Employee is a Person so Employee must be inherit from Person rather than Entity?

    • http://enterprisecraftsmanship.com/ Vladimir Khorikov

      As long as Person itself inherits from Entity, there’s nothing stopping you from doing so, you don’t have to inherit from Entity directly.

      • Subhash

        Thanks for quick response.
        Actually I have more complex scenario like,
        1) Entity Base class
        public abstract class Entity
        {
        }

        public abstract class AuditableEntity : Entity, IAuditableEntity
        {
        public int CreatedBy {get; private set;}
        public DateTime CreatedOn {get; private set;}
        }

        public abstract class AuditableTemporalEntity : AuditableEntity, ITemporalEntity
        {
        public DateTime ValidFrom {get; private set;}
        public DateTime ValidTill {get; private set;}
        }

        public abstract class HistoryEntity: Entity, IHistoryEntity
        {
        public int HistoryId {get; private set;}
        public string Action {get; private set;}
        }

        public class Employee : AuditableTemporalEntity
        {
        }

        public class EmployeeHistory: HistoryEntity
        {
        }

        In each base classes, I have implemented common behaviours like Activate, DeActivate methods in AuditableEntity class etc.

        So, in this case, I have already inherit Person by AuditableTemporalEntity like,

        public abstract class Person: AuditableTemporalEntity
        {
        }

        but now I cannot inherit Person to EmployeeHistory class.

        I have tried by solving this approach by implementing interfaces directly to classes but as you mentioned, it’s violate DRY principle by duplicate properties and behaviours.

        Also tried by generic extension methods but then I have to set public “setters” in interfaces so I can set properties value in extension methods as generic extension methods using constraint by interfaces.