Introduction
Separating entity class mapping using Fluent API will make modification and maintenance easier for midiup or large application/project.
Background
When working with lot of Entity classes in a project, it is difficult to maintain all of the Entity configuration in DbContext
's OnModelCreating
method. For example:
public class ApplicationDbContext : DbContext
{
public ApplicationDbContext()
: base()
{
}
public DbSet<Trainees> Trainees { get; set; }
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
}
}
Now if you have hundreds of Entities, then you have to add all of the entities here which makes modification and maintenance much harder.
Moreover, if you want to override the relationship, Indexing or field property mapping, you may modify the OnModelCreating
method in the following way:
protected override void OnModelCreating(ModelBuilder builder)
{
builder.Entity<Trainee>().ToTable("Trainee");
builder.Entity<Trainee>().HasKey(t => t.Id).Property
(t => t.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
builder.Entity<Trainee>().Property(t => t.TraineeNo).
HasMaxLength(10).IsRequired().IsUnicode();
builder.Entity<Trainee>().Property(t => t.Gender);
builder.Entity<Trainee>().Property(t => t.Name).HasMaxLength(500).IsRequired();
builder.Entity<Trainee>().Property(t => t.FatherName).HasMaxLength(500);
builder.Entity<Trainee>().Property(t => t.MotherName).HasMaxLength(500);
builder.Entity<Trainee>().Property(t => t.NationalId).HasMaxLength(50);
builder.Entity<Trainee>().Property(t => t.MobilNo).HasMaxLength(50);
builder.Entity<Trainee>().Property(t => t.PholeNo).HasMaxLength(50);
builder.Entity<Trainee>().Property(t => t.Email).HasMaxLength(150);
builder.Entity<Trainee>().Property(t => t.LastEducation).HasMaxLength(50);
builder.Entity<Trainee>().Property(t => t.TraineeStatus);
builder.Entity<Trainee>().Property(t => t.RetakeAvailable);
builder.Entity<Trainee>().Property(t => t.Note).HasMaxLength(750);
builder.Entity<Trainee>().Property(t => t.Deleted);
builder.Entity<Trainee>().Property(t => t.DeleteDate);
builder.Entity<Trainee>().HasMany(pr => pr.TraineeRoles)
.WithMany(cr => cr.Trainees)
.Map(m => m.ToTable("Trainee_TraineeRole_Mapping"));
base.OnModelCreating(builder);
}
So we can customize Entity
by EntityTypeConfiguration
class. But it is horrible to maintain when it crosses 10 to 20 entities.
That's why we need to separate each entity configuration in different cs class files.
Using the Code
Create a CS class named TraineeMap.cs. It will inherit EntityTypeConfiguration
. For EntityTypeConfiguration
, you need to use System.Data.Entity.ModelConfiguration namespace
.
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity.ModelConfiguration;
using TIS.Entity.Participant;
namespace TIS.Data.Mapping.Participant
{
public class TraineeMap : EntityTypeConfiguration<Trainee>
{
public TraineeMap()
{
ToTable("Trainee");
HasKey(t => t.Id).Property(t => t.Id).HasDatabaseGeneratedOption
(DatabaseGeneratedOption.Identity);
Property(t => t.TraineeNo).HasMaxLength(10).IsRequired().IsUnicode();
Property(t => t.Gender);
Property(t => t.Name).HasMaxLength(500).IsRequired();
Property(t => t.FatherName).HasMaxLength(500);
Property(t => t.MotherName).HasMaxLength(500);
Property(t => t.NationalId).HasMaxLength(50);
Property(t => t.MobilNo).HasMaxLength(50);
Property(t => t.PholeNo).HasMaxLength(50);
Property(t => t.Email).HasMaxLength(150);
Property(t => t.LastEducation).HasMaxLength(50);
Property(t => t.TraineeStatus);
Property(t => t.RetakeAvailable);
Property(t => t.Note).HasMaxLength(750);
Property(t => t.Deleted);
Property(t => t.DeleteDate);
this.HasMany(pr => pr.TraineeRoles)
.WithMany(cr => cr.Trainees)
.Map(m => m.ToTable("Trainee_TraineeRole_Mapping"));
}
}
}
Now change the OnModelCreating
method as follows:
protected override void OnModelCreating(ModelBuilder builder)
{
builder.Configurations.Add(new TraineeMap());
base.OnModelCreating(builder);
}
Again, the problem here is that for each Entity, we have to repeat the following line:
builder.Configurations.Add(new {EntityClassName}());
How can we eliminate redundancy? Reflection may help us by finding which classes are derived from EntityTypeConfiguration
generic class.
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
var typesToRegister = Assembly.GetExecutingAssembly().GetTypes()
.Where(type => !String.IsNullOrEmpty(type.Namespace))
.Where(type => type.BaseType != null && type.BaseType.IsGenericType &&
type.BaseType.GetGenericTypeDefinition() == typeof(EntityTypeConfiguration<>));
foreach (var type in typesToRegister)
{
dynamic configurationInstance = Activator.CreateInstance(type);
modelBuilder.Configurations.Add(configurationInstance);
}
base.OnModelCreating(modelBuilder);
}
Above, we are filtering from assembly and finding those classes whose type is typeof(EntityTypeConfiguration<>)
and then adding to configuration.
Points of Interest
Separating each entity mapping makes modification and maintenance easier. By applying Reflection, the automation is fulfilled.