MSDN Documentation

Microsoft Developer Network - .NET Concepts

Entity Framework Code First

The Code First approach in Entity Framework (EF) allows you to create a data model by writing C# or VB.NET classes. EF then generates the database schema based on your model. This is ideal for developers who prefer to work with objects and conventions over manually designing database tables.

What is Code First?

Code First flips the traditional Entity Framework workflow. Instead of generating classes from an existing database, you define your domain model using plain .NET classes. Entity Framework then infers the database structure from these classes. This approach aligns well with Domain-Driven Design (DDD) principles and test-driven development (TDD).

Key Benefits

Getting Started with Code First

To use Code First, you typically need to:

  1. Install Entity Framework: Use NuGet Package Manager to install the EntityFramework package.
  2. Define Your Domain Models: Create your C# classes representing entities, for example, Product, Category, etc.
  3. Define Your DbContext: Create a class that derives from System.Data.Entity.DbContext. This class represents your database session and will contain DbSet<TEntity> properties for each of your domain models.
  4. Configure Mappings (Optional): While EF infers mappings by convention, you can use Data Annotations or the Fluent API to customize table names, column properties, relationships, and more.
  5. Create the Database: When your application first runs, EF can automatically create the database or update an existing one based on your model. This is often managed using EF Migrations.

Example: Simple Domain Model

Consider the following simple domain model:


public class Blog
{
    public int BlogId { get; set; }
    public string Name { get; set; }
    public string Url { get; set; }

    public virtual ICollection<Post> Posts { get; set; }
}

public class Post
{
    public int PostId { get; set; }
    public string Title { get; set; }
    public string Content { get; set; }

    public int BlogId { get; set; }
    public virtual Blog Blog { get; set; }
}
            

Example: DbContext

Here's a corresponding DbContext:


using System.Data.Entity;

public class BloggingContext : DbContext
{
    public BloggingContext() : base("name=BloggingDatabase") // Connection string name
    {
    }

    public DbSet<Blog> Blogs { get; set; }
    public DbSet<Post> Posts { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        // Further configurations can be added here using Fluent API
        base.OnModelCreating(modelBuilder);
    }
}
            

Data Annotations

You can use Data Annotations to configure your model directly on your classes:


using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Collections.Generic;

public class Product
{
    [Key] // Marks ProductId as the primary key
    public int ProductId { get; set; }

    [Required] // Makes the Name property non-nullable in the database
    [StringLength(100)] // Sets the maximum length of the Name column
    public string Name { get; set; }

    [Column(TypeName = "decimal(18,2)")] // Specifies the database column type
    public decimal Price { get; set; }

    public int CategoryId { get; set; }
    [ForeignKey("CategoryId")] // Configures the relationship
    public virtual Category Category { get; set; }
}
            

Fluent API

For more complex configurations, the Fluent API provides a powerful way to define mappings within your DbContext:


protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    // Configure entity properties
    modelBuilder.Entity<Product>()
        .HasKey(p => p.ProductId); // Primary Key

    modelBuilder.Entity<Product>()
        .Property(p => p.Name)
        .IsRequired()
        .HasMaxLength(100); // String length constraint

    modelBuilder.Entity<Product>()
        .Property(p => p.Price)
        .HasColumnType("decimal(18,2)"); // Database column type

    // Configure relationships
    modelBuilder.Entity<Product>()
        .HasRequired(p => p.Category) // One-to-many: Product must have a Category
        .WithMany(c => c.Products)   // One-to-many: Category can have many Products
        .HasForeignKey(p => p.CategoryId); // Foreign key property

    // Rename tables
    modelBuilder.Entity<Product>().ToTable("Products");
    modelBuilder.Entity<Category>().ToTable("Categories");

    base.OnModelCreating(modelBuilder);
}
            

Tip:

Entity Framework Migrations are essential for managing changes to your Code First model over time and synchronizing them with your database schema.

Note:

The connection string for your database is typically configured in your application's configuration file (e.g., App.config or Web.config).