As your Entity Framework Core model grows, managing the configuration logic in the OnModelCreating
method can become challenging. To keep the code clean, maintainable, and scalable, it’s important to modularize the entity configurations. In this article, we’ll explore three approaches to clean up the configuration logic in OnModelCreating
:
- Using
IEntityTypeConfiguration
for theProduct
entity - Using Extension Methods for the
Category
entity - Using Partial Classes for the
ProductSupplier
entity
1. Using IEntityTypeConfiguration
for Product
IEntityTypeConfiguration
is a great way to modularize the configuration logic for each entity into its own class. Let’s see how we can use this approach to configure the Product
entity.
Step 1: Create the ProductConfiguration
Class
Create a new class ProductConfiguration.cs
to configure the Product
entity separately:
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
public class ProductConfiguration : IEntityTypeConfiguration<Product>
{
public void Configure(EntityTypeBuilder<Product> builder)
{
builder.Property(p => p.Price)
.HasColumnType("decimal(18,2)");
// One-to-One relationship with Inventory
builder.HasOne(p => p.Inventory)
.WithOne(i => i.Product)
.HasForeignKey<Inventory>(i => i.ProductId);
}
}
Step 2: Apply Configuration in AppDbContext
In AppDbContext
, use ApplyConfiguration
to apply the Product
configuration:
public class AppDbContext : DbContext
{
public DbSet<Product> Products { get; set; }
public DbSet<Category> Categories { get; set; }
public DbSet<Inventory> Inventories { get; set; }
public DbSet<Supplier> Suppliers { get; set; }
public DbSet<ProductSupplier> ProductSuppliers { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
// Apply Product configuration using IEntityTypeConfiguration
modelBuilder.ApplyConfiguration(new ProductConfiguration());
}
}
This approach separates the Product
configuration logic, making the AppDbContext
cleaner and easier to maintain.
2. Using Extension Methods for Category
Using extension methods is another great way to modularize configuration logic for an entity. Let’s apply this approach to the Category
entity.
Step 1: Create Extension Method
Create an extension method to configure the Category
entity in a new file called ModelBuilderExtensions.cs
:
public static class ModelBuilderExtensions
{
public static void ConfigureCategory(this ModelBuilder modelBuilder)
{
modelBuilder.Entity<Category>(entity =>
{
entity.HasKey(c => c.Id);
entity.Property(c => c.Name).IsRequired().HasMaxLength(50);
// One-to-Many relationship with Products
entity.HasMany(c => c.Products)
.WithOne(p => p.Category)
.HasForeignKey(p => p.CategoryId);
});
}
}
Step 2: Apply Extension Method in AppDbContext
In AppDbContext
, use the extension method to apply the Category
configuration:
public class AppDbContext : DbContext
{
public DbSet<Product> Products { get; set; }
public DbSet<Category> Categories { get; set; }
public DbSet<Inventory> Inventories { get; set; }
public DbSet<Supplier> Suppliers { get; set; }
public DbSet<ProductSupplier> ProductSuppliers { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
// Apply Product configuration using IEntityTypeConfiguration
modelBuilder.ApplyConfiguration(new ProductConfiguration());
// Apply Category configuration using extension method
modelBuilder.ConfigureCategory();
}
}
Using extension methods for the Category
configuration makes it easier to extend and maintain your code.
3. Using Partial Classes for ProductSupplier
When you have complex relationships like Many-to-Many configurations, using partial classes allows you to distribute the configuration logic across multiple files, keeping the code modular and clean. Let’s apply this approach to configure the ProductSupplier
entity.
Step 1: Create Partial Class for ProductSupplier
Configuration
Create a new partial class in a separate file named AppDbContext.ProductSupplierConfiguration.cs
to configure the ProductSupplier
entity:
public partial class AppDbContext : DbContext
{
private void ConfigureProductSupplier(ModelBuilder modelBuilder)
{
modelBuilder.Entity<ProductSupplier>()
.HasKey(ps => ps.Id); // Define primary key for ProductSupplier
modelBuilder.Entity<ProductSupplier>()
.HasOne(ps => ps.Product) // Configure the relationship to Product
.WithMany(p => p.ProductSuppliers)
.HasForeignKey(ps => ps.ProductId);
modelBuilder.Entity<ProductSupplier>()
.HasOne(ps => ps.Supplier) // Configure the relationship to Supplier
.WithMany(s => s.ProductSuppliers)
.HasForeignKey(ps => ps.SupplierId);
modelBuilder.Entity<ProductSupplier>()
.ToTable("ProductSuppliers"); // Define the table name
}
}
Step 2: Modify OnModelCreating
to Call the Partial Class Method
Now, in the main AppDbContext
class, call the ConfigureProductSupplier
method in OnModelCreating
:
public partial class AppDbContext : DbContext
{
public DbSet<Product> Products { get; set; }
public DbSet<Category> Categories { get; set; }
public DbSet<Inventory> Inventories { get; set; }
public DbSet<Supplier> Suppliers { get; set; }
public DbSet<ProductSupplier> ProductSuppliers { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
// Apply Product configuration using IEntityTypeConfiguration
modelBuilder.ApplyConfiguration(new ProductConfiguration());
// Apply Category configuration using extension method
modelBuilder.ConfigureCategory();
// Apply ProductSupplier configuration using partial class method
ConfigureProductSupplier(modelBuilder);
}
}
By splitting the configuration logic for ProductSupplier
into a partial class, the code is easier to manage, especially as the number of entities and relationships grows.
Conclusion
By applying these techniques, we achieve a more modular, maintainable, and scalable codebase in Entity Framework Core:
-
Using
IEntityTypeConfiguration
for theProduct
entity ensures that each entity has its configuration class, which improves modularity. -
Using Extension Methods for the
Category
entity provides a flexible way to apply configurations that can be reused across different contexts. -
Using Partial Classes for the
ProductSupplier
entity allows you to split large and complex configurations into smaller, more manageable pieces, keeping theDbContext
class clean.
These strategies will help you maintain a cleaner OnModelCreating
method and improve the maintainability of your codebase.
Source Code EFCoreDemo
Top comments (0)