Skip to main content

Command Palette

Search for a command to run...

Entity Framework Core - Code First Approach

Updated
•4 min read•View as Markdown

1. What is Code First?

In the Code First approach, you write your C# classes (Entities) first, and EF Core creates the database tables based on those classes. Your code is the "Source of Truth."

If you change your C# class (e.g., add a property), you run a Migration, and EF Core updates the database schema to match.


2. The Workflow

  1. Define Models: Create C# classes (User, Product).

  2. Configure Context: Create a DbContext class to manage these models.

  3. Add Migration: Generate a script (C# code) that describes how to create the DB.

  4. Update Database: Apply that script to the actual SQL database.


3. Step-by-Step Implementation

Step A: Install NuGet Packages

You need the EF Core tools and the provider for your specific database (e.g., SQL Server).

dotnet add package Microsoft.EntityFrameworkCore.SqlServer
dotnet add package Microsoft.EntityFrameworkCore.Tools

Step B: Create Entity Classes (POCOs)

These are plain C# classes. By default, EF Core maps Id to the Primary Key.

public class Product
{
    public int Id { get; set; }           // Primary Key
    public string Name { get; set; }      // Column: nvarchar(max)
    public decimal Price { get; set; }    // Column: decimal(18,2)
    public bool IsInStock { get; set; }   // Column: bit
}

Step C: Create the DbContext

This class acts as the bridge between your code and the database.

using Microsoft.EntityFrameworkCore;

public class AppDbContext : DbContext
{
    // 1. Constructor to accept options (connection string, etc.)
    public AppDbContext(DbContextOptions<AppDbContext> options) : base(options)
    {
    }

    // 2. DbSets: represent the tables in your DB
    public DbSet<Product> Products { get; set; }
}

Step D: Configuration (Dependency Injection)

In your Program.cs (for ASP.NET Core), register the context with a connection string.

var connectionString = "Server=myServer;Database=MyCodeFirstDb;Trusted_Connection=True;";

builder.Services.AddDbContext<AppDbContext>(options =>
    options.UseSqlServer(connectionString));

4. Migration Commands

Migrations are the heart of Code First. They track changes to your model over time.

Command (CLI)Description
dotnet ef migrations add InitialCreateScans your code, compares it to the last snapshot, and creates a migration file (C#) to bridge the gap.
dotnet ef database updateTranslates the migration file into SQL and executes it on the database.
dotnet ef migrations removeDeletes the last migration (only if it hasn't been applied to the DB yet).
dotnet ef migrations scriptGenerates a raw SQL script (useful for production deployment).

Behind the Scenes:

EF Core creates a table called __EFMigrationsHistory in your database. It uses this to check which migrations have already been applied so it doesn't run them twice.


5. Configuring the Schema

EF Core is smart, but sometimes you need to override its assumptions (e.g., making a string required or limiting its length). You have three ways to do this, in order of precedence:

A. Conventions (Default)

EF Core guesses based on naming.

  • Property named Id -> Primary Key.

  • string -> nullable nvarchar(max).

  • int -> non-nullable int.

B. Data Annotations (Attributes)

Add attributes directly to your class properties.

public class Product
{
    [Key] // Explicit Primary Key
    public int ProductKey { get; set; }

    [Required] // Not Null
    [MaxLength(100)] // nvarchar(100)
    public string Name { get; set; }

    [NotMapped] // Do not create a column for this
    public string TempData { get; set; }
}

C. Fluent API (Most Powerful)

Defined in OnModelCreating inside your DbContext. This keeps your entity classes clean.

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Product>()
        .Property(p => p.Name)
        .IsRequired()
        .HasMaxLength(100);

    modelBuilder.Entity<Product>()
        .ToTable("tbl_Products"); // Custom table name
}

6. Data Seeding (Initial Data)

You can use Code First to populate the database with default data (like Admin users or Lookup values) automatically.

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Product>().HasData(
        new Product { Id = 1, Name = "Laptop", Price = 999.99m, IsInStock = true },
        new Product { Id = 2, Name = "Mouse", Price = 25.50m, IsInStock = true }
    );
}
  • Note: When you run add-migration, EF converts this into SQL INSERT statements.

7. Handling Changes (Evolution)

Code First is designed for evolving databases.

  1. Modify Code: You add a new property public string SKU { get; set; } to Product.

  2. Add Migration: Run dotnet ef migrations add AddedSkuToProduct.

  3. Update DB: Run dotnet ef database update.

  4. Result: EF Core sends an ALTER TABLE command to the database to add the column without losing existing data.


8. Advantages vs. Disadvantages

AdvantagesDisadvantages
Version Control: Your DB schema lives in Git (as C# code).Complexity: Mapping complex legacy DB schemas to code can be difficult manually.
Speed: Rapid development; no need to switch context to SQL Management Studio.Data Risks: Careless migrations (e.g., renaming a column) can result in data loss if not reviewed.
Type Safety: You work with strongly typed objects immediately.Learning Curve: Understanding Fluent API for advanced relationships takes time.

Summary Checklist for Code First

  1. Write Code: Define Entities (class).

  2. Link: Add DbSet<T> to DbContext.

  3. Connect: Configure connection string in Program.cs.

  4. Create: dotnet ef migrations add Init.

  5. Push: dotnet ef database update.

More from this blog

E

EF Core

31 posts