This content originally appeared on DEV Community and was authored by mohamed Tayel
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
IEntityTypeConfigurationfor theProductentity - Using Extension Methods for the
Categoryentity - Using Partial Classes for the
ProductSupplierentity
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)
{
// Configure properties
builder.Property(p => p.Name)
.HasField("_name"); // Use backing field for Name
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
IEntityTypeConfigurationfor theProductentity ensures that each entity has its configuration class, which improves modularity. -
Using Extension Methods for the
Categoryentity provides a flexible way to apply configurations that can be reused across different contexts. -
Using Partial Classes for the
ProductSupplierentity allows you to split large and complex configurations into smaller, more manageable pieces, keeping theDbContextclass clean.
These strategies will help you maintain a cleaner OnModelCreating method and improve the maintainability of your codebase.
Source Code EFCoreDemo
This content originally appeared on DEV Community and was authored by mohamed Tayel
mohamed Tayel | Sciencx (2024-09-13T20:49:10+00:00) EFCore Tutorial P4:Cleaning Up `OnModelCreating`. Retrieved from https://www.scien.cx/2024/09/13/efcore-tutorial-p4cleaning-up-onmodelcreating/
Please log in to upload a file.
There are no updates yet.
Click the Upload button above to add an update.