Move Fluent API Configurations to a Separate Class in Entity Framework

As you have seen in the previous chapters, we configured all the domain classes using Fluent-API in the OnModelCreating() method. However, it becomes hard to maintain if you configure a large number of domain classes in the OnModelCreating. EF 6 allows you to create a separate class for each entity and place all the configurations related to an entity.

Consider the following example where we configured the Student entity.

public class SchoolDBContext: DbContext 
{
    public SchoolDBContext(): base() 
    {
    }

    public DbSet<Student> Students { get; set; }
        
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
            modelBuilder.Entity<Student>().ToTable("StudentInfo");
                
            modelBuilder.Entity<Student>().HasKey<int>(s => s.StudentKey);
                
            modelBuilder.Entity<Student>()
                    .Property(p => p.DateOfBirth)
                    .HasColumnName("DoB")
                    .HasColumnOrder(3)
                    .HasColumnType("datetime2");

            modelBuilder.Entity<Student>()
                    .Property(p => p.StudentName)
                    .HasMaxLength(50);
                        
                modelBuilder.Entity<Student>()
                    .Property(p => p.StudentName)
                    .IsConcurrencyToken();
                
            modelBuilder.Entity<Student>()
                .HasMany<Course>(s => s.Courses)
                .WithMany(c => c.Students)
                .Map(cs =>
                        {
                            cs.MapLeftKey("StudentId");
                            cs.MapRightKey("CourseId");
                            cs.ToTable("StudentCourse");
                        });
    }
}

Now, you can move all the configurations related to the Student entity to a separate class which derives from EntityTypeConfiguration<TEntity>. Consider the following StudentEntityConfigurations class which includes all the configurations for the Student entity.

public class StudentEntityConfiguration: EntityTypeConfiguration<Student>
{
    public StudentEntityConfiguration()
    {
            this.ToTable("StudentInfo");
                
            this.HasKey<int>(s => s.StudentKey);
                
            this.Property(p => p.DateOfBirth)
                    .HasColumnName("DoB")
                    .HasColumnOrder(3)
                    .HasColumnType("datetime2");

            this.Property(p => p.StudentName)
                    .HasMaxLength(50);
                        
            this.Property(p => p.StudentName)
                    .IsConcurrencyToken();
                
            this.HasMany<Course>(s => s.Courses)
                .WithMany(c => c.Students)
                .Map(cs =>
                        {
                            cs.MapLeftKey("StudentId");
                            cs.MapRightKey("CourseId");
                            cs.ToTable("StudentCourse");
                        });
    }
}

As you can see above, we have moved all the configurations for the Student entity into the constructor of StudentEntityConfiguration, which is derived from EntityTypeConfiguration<Student>. You need to specify the entity type for which you include the configurations (Student in this case) in a generic place holder.

Now, you need to add this custom configuration class using Fluent API, as shown below.

public class SchoolDBContext: DbContext 
{
    public SchoolDBContext(): base() 
    {
    }

    public DbSet<Student> Students { get; set; }
        
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        // Moved all Student related configuration to StudentEntityConfiguration class
        modelBuilder.Configurations.Add(new StudentEntityConfiguration());
    }
}

Thus, you can use multiple configuration classes to increase the readability and maintainability.