Custom Entity Type Configurations in Entity Framework Code First (Part 1)

Published on Wednesday, April 17, 2013

One of the things I really like about Entity Framework Code First is the way you can mix declarative configuration (I.e., by using Data Annotation attributes) with programmatic configuration for more complicated cases (I.e., by using the fluent API). The one aspect of this that really bothers me though is that in normal usage the fluent API commands end up being placed inside your DbContext class removed from your actual entity. If you change some aspect of an entity that uses the fluent API for configuration, you have to remember to go check the OnModelCreating() method to ensure you don't need to modify the code-based configuration. It would be much better (in my opinion) if all configuration, declarative and programmatic, were located close to the entity and/or encapsulated within it. This article explains one way of accomplishing this.

The first thing you'll need to understand is the way that the fluent API actually configures entities. Inside of the DbContext class (which you've presumably subclassed) there is an overridable method called OnModelCreating(). This method has a single parameter of type DbModelBuilder. During normal fluent API usage you write code that looks like this inside the OnModelCreating() method:

modelBuilder.Entity<Department>().Property(t => t.Name).IsRequired();

When you call DbModelBuilder.Entity<TEntityType>(), you get back an EntityTypeConfiguration<TEntityType> class that is used for configuring the entity. However, this isn't the only way to get an EntityTypeConfiguration class. You can actually create them yourself:

public class DepartmentTypeConfiguration : EntityTypeConfiguration<Department>
{
  public DepartmentTypeConfiguration() { }
}

Once you've instantiated one, you can use it just like you would have used the one you obtained from the DbModelBuilder.Entity<TEntityType>() call:

DepartmentTypeConfiguration departmentConfig = new DepartmentTypeConfiguration();
departmentConfig.Property(t => t.Name).IsRequired();

The previous example was just to show that the custom EntityTypeConfiguration class works the same way as the ones you obtain by calling DbModelBuilder.Entity<TEntityType>(). Alternatively you can specify configuration code in the constructor, which is more useful because it means the configuration code will get called whenever a new instance of your EntityTypeConfiguration class is created (I.e., through reflection).

public class DepartmentTypeConfiguration : EntityTypeConfiguration<Department>
{
  public DepartmentTypeConfiguration()
  {
    Property(t => t.Name).IsRequired();
  }
}

The fluent API calls (such as Property()) change the internal state of the EntityTypeConfiguration class. When all of the configuration is complete, Entity Framework reads the state of all EntityTypeConfiguration classes that have been registered and uses them to build the model. But back up a step, notice I said "all EntityTypeConfiguration classes that have been registered". There is one more step before a custom EntityTypeConfiguration class can be used for configuration - it has to be registered with the ConfigurationRegistrar. To do so, you just use the DbModelBuilder.Configurations property:

modelBuilder.Configurations.Add(departmentConfig);

This adds the custom EntityTypeConfiguration instance to the list of configurations that will be used to build the final model. At this point, we could just reflect over the assembly looking for EntityTypeConfiguration classes, instantiating them, and adding them to the ConfigurationRegistrar (as described by Jonas Cannehag):

var typesToRegister = Assembly.GetAssembly(typeof(YourDbContext)).GetTypes()
  .Where(type => type.Namespace != null
    && type.Namespace.Equals(typeof(YourDbContext).Namespace))
  .Where(type => type.BaseType.IsGenericType
    && type.BaseType.GetGenericTypeDefinition() == typeof(EntityTypeConfiguration<>));

foreach (var type in typesToRegister)
{
  dynamic configurationInstance = Activator.CreateInstance(type);
  modelBuilder.Configurations.Add(configurationInstance);
}

This will allow you to create as many custom EntityTypeConfiguration classes as you need for each entity in your model. However, there are some limitations:

  • The ConfigurationRegistrar.Add() method only allows one EntityTypeConfiguration class per entity type. This may be a problem in complex models if you have some configurations for a given entity spread out in multiple places (for example, you want to place the responsibility of configuring relationships for a given entity near the entities on the other side of the relationships).
  • I personally find the idea of placing configuration code inside the constructor of a dedicated class a little awkward. I would prefer to have my custom configurations specified through an interface that I could implement right on the entity, or perhaps use more than once to specify configuration for multiple entities in a single configuration class. That would give more flexibility.

In my next post I'll discuss an alternate method of specifying custom entity type configurations that builds on this technique and addresses these two points.

comments powered by Disqus