Base Class

Domain classes are an important part of your application. A base class can be beneficial whether you are building a small project or an enterprise solution. You should follow some basic principles for creating these classes. For this example, I’m choosing to use Entity Framework Code First that targets MS SQL Server database. Now, let’s create a class library in our new solution, and then add a simple base class:

using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace MyDomainClasses
{
    public abstract class EntityBase
    {
        protected EntityBase()
        {
                DateCreated = DateTime.Now;
                DateModified = DateTime.Now;
        }

        [Key]
        public int Id { get; protected set; }

        [Column(TypeName = "datetime2")]
        public DateTime? DateCreated { get; set; }

        [Column(TypeName = "datetime2")]
        public DateTime? DateModified { get; set; }

    }

}

The base class is public static abstract, which ensures that all three fields will be included with all derived classes, while keeping us DRY . Using a simple default constructor, DateCreated and DateModified are set with the current date and time when new derived entities are created. I use “protected” for the Id setter and for the constructor, so that they can only be accessed in code by the same class, or derived classes, which is what we are providing for in this implementation.

Another advantage of using a public static abstract base class is data annotations. In this example I have provided an annotation for Id, declaring that it will be both the primary key and an identity field. In addition, I’ve used a schema annotation to instruct SQL Server to use datetime2 type (the preferred date type for SQL 2008 and forward) for greater precision.

The Key annotation is actually superfluous in this particular example because; Code First infers that a property is a primary key if a property on a class is named “ID” (not case sensitive), or the class name followed by “ID”. If the type of the primary key property is numeric or GUID it will be configured as an identity column. Entity Framework has a number of data annotations , as well as a fluent API for mappings and configurations.

C# doesn’t allow multiple inheritance from classes, but does allow you to implement multiple interfaces. If you have fields that only appear in some classes, you can use an Interface. Let’s add an Interface for last and first name:

namespace MyDomainClasses
{
    interface IPerson
    {
        string Lname { get; set; }
        string Fname { get; set; }
    }
}

Now let’s discuss a potential pitfall when creating derived entity classes. C# provides a default parameterless constructor for classes that do not contain a constructor, so that the class can be instantiated. Say you create a constructor with parameters in a new derived class to control how users will instantiate it. As a result, now the default parameterless constructor is no longer available, as shown here:

using System;

namespace MyDomainClasses
{
    public class Staff : EntityBase, IPerson
    {

        public Staff( string lname, string fname, double hourlyRate)
        {
            this.Lname = lname;
            this.Fname = fname;
            this.HourlyRate = hourlyRate;
            this.Notes = "I love lamp.";
        }

        public string Lname { get; set; }

        public string Fname { get; set; }

        public DateTime? DateOfBirth { get; set; }

        public double HourlyRate { get; set; }

        public string Notes { get; private set; }

    }
}

So, you have taken control of your class, but this necessitates knowing how other parts of your solution will interact with that class. For example, Julie Lerman explains in her blog that Entity Framework requires a parameterless constructor in order to materialize objects returned from queries (or loading).

Well, now what? If we have to use a parameterless constructor, can it be private? Fortunately, yes. Entity Framework will work with a private parameterless constructor, but for it to work in all scenarios (e.g. lazy loading), consider using protected:

namespace MyDomainClasses
{
    public class Staff : EntityBase, IPerson
    {
        protected Staff()
        {
        }

        public Staff( string lname, string fname, double hourlyRate)
        {
            this.Lname = lname;
            this.Fname = fname;
            this.HourlyRate = hourlyRate;
            this.Notes = "I love lamp.";
        }

        public string Lname { get; set; }
        public string Fname { get; set; }

        public DateTime? DateOfBirth { get; set; }

        public double HourlyRate { get; set; }

        public string Notes { get; private set; }

    }
}

This problem is not exclusive to the example we’ve looked at above. The reason Entity Framework needed that parameterless constructor in this context, is because it uses reflection to discover the properties of the model. There may be other APIs that interact with your class that also use reflection. Consider using this pattern in any of these situations.

If you are dealing with a larger domain, you can build on this simple class, and add generics and equality checks to handle more situations. Check out this example where Chris Pratt (No, not that Chris Pratt!) goes nuclear generic with his base class! There are many other examples out there, and I encourage you to search for, and find the ones that click with you. Keep your code clean, simple, and understandable.

Next time we’ll refactor the Interface we added and explore the advantages of using Value Objects, as I gently nudge you 😉 towards the path of Domain Driven Design.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s