Entity Framework Core Mastery

The Fluent API Deep Dive (OnModelCreating)

1 Views Updated 5/4/2026

The Fluent API Deep Dive (OnModelCreating)

The Fluent API is the enterprise standard for configuring Entity Framework Core. By overriding the OnModelCreating method inside your DbContext, you achieve absolute, microscopic control over how your physical SQL database is generated, far beyond the limits of visual Data Annotations.

1. Basic Fluent Configurations

Instead of polluting the C# Entity with attributes, we define the relational mapping rules cleanly in one centralized location.

public class ApplicationDbContext : DbContext
{
    public DbSet<Product> Products { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        // Target the specific Entity
        modelBuilder.Entity<Product>(entity => 
        {
            // Table mapping
            entity.ToTable("Inventory_Products");

            // Primary Key definition
            entity.HasKey(p => p.Id);

            // Property configurations
            entity.Property(p => p.Name)
                  .IsRequired()
                  .HasMaxLength(100)
                  .HasColumnName("Product_Name");

            // Precision for Currency
            entity.Property(p => p.Price)
                  .HasPrecision(18, 2);
        });
    }
}

2. Advanced Features Unavailable in Data Annotations

There are specific configurations that can only be achieved using the Fluent API.

Default SQL Values

// Instead of setting a default value in C#, we instruct SQL Server to run the  
// GETDATE() function natively in the database whenever a new row is inserted.
modelBuilder.Entity<Product>()
            .Property(p => p.CreatedDate)
            .HasDefaultValueSql("GETDATE()");

Composite Primary Keys

A composite key is a Primary Key made from combining two columns. Data Annotations physically cannot define this in EF Core.

// The StudentId and CourseId combined form the unique identifier
modelBuilder.Entity<Enrollment>()
            .HasKey(e => new { e.StudentId, e.CourseId });

Filtered Indexes

Creating an index on an Email column speeds up logins. But what if we only want to enforce Unique Emails on accounts that are NOT deleted?

modelBuilder.Entity<User>()
            .HasIndex(u => u.Email)
            .IsUnique()
            .HasFilter("[IsDeleted] = 0"); // A highly optimized SQL Index!

3. Extracting Configs (IEntityTypeConfiguration)

If you have 100 tables, your OnModelCreating method will be 5,000 lines long. We fix this by extracting configurations into dedicated classes.

public class ProductConfiguration : IEntityTypeConfiguration<Product>
{
    public void Configure(EntityTypeBuilder<Product> builder)
    {
        builder.ToTable("Products");
        builder.Property(p => p.Name).IsRequired();
    }
}

// Inside DbContext:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    // Automatically scans the entire project and applies all configurations!
    modelBuilder.ApplyConfigurationsFromAssembly(typeof(ApplicationDbContext).Assembly);
}

4. Interview Mastery

Q: "If a developer places a `[MaxLength(50)]` Data Annotation on a property, but the Architect writes a Fluent API rule limiting that exact same property to `HasMaxLength(100)`, which rule actually gets applied to the SQL database?"

Architect Answer: "The Fluent API will aggressively override the Data Annotation. EF Core processes model building in a strict sequence: First, it applies Default Conventions. Second, it applies Data Annotations. Finally, it executes the Fluent API in `OnModelCreating`. Because the Fluent API is processed last, its configurations are considered the absolute final authority in the framework and will overwrite any conflicting rules established by the attributes."

Entity Framework Core Mastery
1. Foundations & Architecture
Introduction to Object Relational Mapping (ORM) Entity Framework Core Architecture & Providers Setup and DbContext Integration Code-First vs Database-First Approaches Reverse Engineering Existing Databases (Scaffolding)
2. Code-First Modeling
Entity Conventions & Data Annotations The Fluent API Deep Dive (OnModelCreating) Primary Keys, Composite Keys, & Guids Required Properties & Database Defaults Value Conversions (Enums & Strongly Typed IDs)
3. Relational Architecture
One-to-Many Relationships & Foreign Keys One-to-One Relationships (Dependent Entities) Many-to-Many Relationships & Navigation Properties Owned Entity Types (Value Objects) Table-per-Hierarchy (TPH) Inheritance
4. Data Querying & LINQ
Basic LINQ Queries & IQueryable Execution Tracking vs No-Tracking Queries (Performance) Eager Loading vs Explicit Loading (Include) Lazy Loading Pitfalls & Proxies Client vs Server Evaluation Parsing
5. Manipulating Data (CUD)
Adding, Updating, and Removing Entities The ChangeTracker and Entity States Disconnected Entities in Web APIs Batch Updates and Deletes (.NET 7+)
6. Advanced Performance & Scale
Concurrency Tokens and Optimistic Locking Raw SQL Queries and Views (FromSqlRaw) Compiled Queries for High Throughput Interceptors (Logging & Auditing Data Changes) DbContext Pooling Mechanisms Managing Complex EF Core Migrations (CI/CD)