With EF Core, you configure your entities (e.g. tables) using the OnModelCreating in your database context. It is easy to just put all of the configurations into that OnModelCreating method which for just a few entities works great. However, as the number of entities grows, OnModelCreating easily becomes unwieldy with thousands of lines of configuration code.
In this post, I am going to show you how you can move the configuration for each of your entities to it’s own file and just have to put a single line of code in the OnModelCreating for each entity. This will greatly simplify the management and maintenance of the entity configuration code.
Problem We Are Solving
Lets take a look at an example of the OnModelCreation method. As you can see below with just 2 entities, we are already looking at 26 lines of configuration code for just a couple of indexes, a query filter, and an enum based column.
If we stopped at just 26 lines of code, no big deal but as the number of entities grows so does the amount of configuration code. In fact, one of the projects I am currently working on has over 2,000 lines of configuration code.
|
|
After we are done with moving the configurations for each entities into their own file, the OnModelCreating method will only contain a single line for each entity that we need to configure. This is way easier to manage.
Here is what the OnModelCreating will look like after our implementation
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.ApplyConfiguration(new BlogMap());
modelBuilder.ApplyConfiguration(new PostMap());
}
Solution
This post builds on the sample code from our previous post. You can download this code here
In order to move the configuration for each entity to its own file, we need to create a class for each entity that implements Microsoft.EntityFrameworkCore.IEntityTypeConfiguration.
Blog Configuration
Create directory Maps
In the Maps directory, create the file BlogMap.cs
Add the following code to the BlogMap.cs file
using EntityFrameworkExample.Entities; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; namespace EntityFrameworkExample.Maps; public class BlogMap : IEntityTypeConfiguration<Blog> { public void Configure(EntityTypeBuilder<Blog> builder) { builder.HasQueryFilter(t => t.IsDeleted == false); builder.HasIndex(t => t.Url) .IsUnique(); builder.Property(s => s.Status) .HasDefaultValue(Status.Draft) .HasConversion<string>(); } }
Post Configuration
In the Maps directory, create the file PostMap.cs
Add the following code to the PostMap.cs file
using EntityFrameworkExample.Entities; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; namespace EntityFrameworkExample.Maps; public class PostMap : IEntityTypeConfiguration<Post> { public void Configure(EntityTypeBuilder<Post> builder) { builder.HasQueryFilter(t => t.IsDeleted == false); builder.HasIndex(t => t.Title); builder.HasIndex(t => t.Url) .IsUnique(); builder.HasIndex(t => new { t.Title, t.Url }); } }
Database Context Update
Now we need to update our database context to use the new BlogMap and PostMap classes.
Open our model context and replace the code within the OnModelCreating method with the following code.
modelBuilder.ApplyConfiguration(new BlogMap());
modelBuilder.ApplyConfiguration(new PostMap());
Conclusion
We have gone from having lots of entity configuration code in the database context OnModelCreating to have just a few lines. Also, having a config file for each entity, makes it possible to quickly see the entity’s configuration.
We can also enhance our implementation which we are going to do in our next post, to have a base class that all entities inherit from where we can put global configurations and not have to worry about adding them to each entity.