Skip to content

Entity Framework Core — Complete Guide

DodaTech Updated 2026-06-28 6 min read

In this tutorial, you will learn about Entity Framework Core. We cover key concepts, practical examples, and best practices to help you master this topic.

Hook

Entity Framework Core (EF Core) is the modern object-relational mapper for .NET. It lets you work with databases using C# objects, eliminating the need to write most SQL queries manually. EF Core handles everything from schema creation to complex joins, enabling you to focus on business logic.

Learning Path

graph LR
  A[EF Core] --> B[DbContext]
  A --> C[Entity Mapping]
  B --> D[Migrations]
  B --> E[LINQ Queries]
  C --> F[Relationships]
  style A fill:#4a90d9,color:#fff
  style B fill:#4a90d9,color:#fff
  style C fill:#4a90d9,color:#fff
  style D fill:#4a90d9,color:#fff
  style E fill:#4a90d9,color:#fff
  style F fill:#4a90d9,color:#fff

Setting Up EF Core

First, install the required packages and define your entities.

// Install: dotnet add package Microsoft.EntityFrameworkCore.SqlServer
//         dotnet add package Microsoft.EntityFrameworkCore.Tools

using Microsoft.EntityFrameworkCore;

public class Blog
{
    public int BlogId { get; set; }
    public string Url { get; set; } = "";
    public int Rating { get; set; }

    public List<Post> Posts { get; set; } = new();
}

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

    public int BlogId { get; set; }
    public Blog Blog { get; set; } = null!;
}

DbContext

The DbContext class manages database connections and tracks entity changes.

public class BloggingContext : DbContext
{
    public DbSet<Blog> Blogs { get; set; }
    public DbSet<Post> Posts { get; set; }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseSqlServer(
            @"Server=(localdb)\mssqllocaldb;Database=Blogging;Trusted_Connection=True");
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        // Configure entity mappings
        modelBuilder.Entity<Blog>()
            .Property(b => b.Url)
            .HasMaxLength(500)
            .IsRequired();

        modelBuilder.Entity<Post>()
            .HasOne(p => p.Blog)
            .WithMany(b => b.Posts)
            .HasForeignKey(p => p.BlogId)
            .OnDelete(DeleteBehavior.Cascade);
    }
}

Migrations

Migrations keep your database schema in sync with your model classes.

# Create a migration
dotnet ef migrations add InitialCreate

# Apply migrations to database
dotnet ef database update

# Generate SQL script
dotnet ef migrations script
// Programmatic migration
using var context = new BloggingContext();
await context.Database.MigrateAsync();

CRUD Operations

Perform create, read, update, and delete operations through LINQ.

using (var db = new BloggingContext())
{
    // Create
    var blog = new Blog { Url = "https://example.com", Rating = 5 };
    db.Blogs.Add(blog);
    db.SaveChanges();
    Console.WriteLine($"Created blog with ID: {blog.BlogId}");

    // Read
    var blogs = db.Blogs
        .Where(b => b.Rating >= 3)
        .OrderByDescending(b => b.Rating)
        .ToList();
    Console.WriteLine($"Found {blogs.Count} blogs");

    // Update
    var existing = db.Blogs.Find(blog.BlogId);
    if (existing != null)
    {
        existing.Rating = 4;
        db.SaveChanges();
        Console.WriteLine("Rating updated");
    }

    // Delete
    db.Blogs.Remove(existing!);
    db.SaveChanges();
    Console.WriteLine("Blog deleted");
}

Relationships

EF Core supports one-to-one, one-to-many, and many-to-many relationships.

// Many-to-many (EF Core 5+)
public class Student
{
    public int StudentId { get; set; }
    public string Name { get; set; } = "";
    public List<Course> Courses { get; set; } = new();
}

public class Course
{
    public int CourseId { get; set; }
    public string Title { get; set; } = "";
    public List<Student> Students { get; set; } = new();
}

// OnModelCreating
modelBuilder.Entity<Student>()
    .HasMany(s => s.Courses)
    .WithMany(c => c.Students)
    .UsingEntity(j => j.ToTable("Enrollments"));

Query with Eager Loading

Control how related data is loaded.

using (var db = new BloggingContext())
{
    // Eager loading
    var blogsWithPosts = db.Blogs
        .Include(b => b.Posts)
        .ThenInclude(p => p.Comments)
        .ToList();

    // Explicit loading
    var blog = db.Blogs.Find(1);
    db.Entry(blog).Collection(b => b.Posts).Load();

    // Filtered include
    var blogs = db.Blogs
        .Include(b => b.Posts.Where(p => p.Title.Contains(".NET")))
        .ToList();
}

Common Mistakes

  1. The N+1 query problem: Avoid lazy loading in loops. Use Include with eager loading or project with Select.

  2. Not using async methods: Always use SaveChangesAsync, ToListAsync, FirstOrDefaultAsync in web applications to avoid thread pool starvation.

  3. Tracking overhead for read-only queries: Use AsNoTracking() for queries that only display data without updating it.

  4. Ignoring migrations in production: Use dotnet ef migrations script to generate SQL scripts for production deployment review.

  5. Loading entire tables: Always use Where, Select, and pagination (Skip/Take) instead of ToList() on the entire DbSet.

Practice Questions

  1. Create a Product and Category relationship with proper foreign keys and write a query that fetches products by category.

  2. Implement a Repository Patternory" >}} pattern that abstracts EF Core operations behind an interface for testability.

  3. Write a Migration that adds an IsDeleted column for soft delete functionality.

  4. Challenge: Build a multi-tenant database architecture where each tenant's data is isolated by a TenantId column.

FAQ

What is the difference between EF6 and EF Core?

EF Core is a complete rewrite that is cross-platform, lighter, and supports modern C# features. EF6 is Windows-only and no longer actively developed.

Should I use the repository pattern with EF Core?

EF Core's DbSet already implements the repository and unit of work patterns. An extra repository layer adds abstraction but may not be necessary for most applications.

How do I handle database connections in web applications?

Register DbContext as a scoped service with AddDbContext. The container manages connection lifetime per request.

Can EF Core work with NoSQL databases?

EF Core is primarily relational. For NoSQL, use dedicated SDKs (MongoDB.Driver, Azure Cosmos SDK) or the EF Core Cosmos DB provider.

How do I view the SQL generated by EF Core?

Configure logging: optionsBuilder.LogTo(Console.WriteLine, LogLevel.Information) or use the ToQueryString() method on IQueryable.

Mini Project: Blog Engine

Build a simple blog data access layer with EF Core.

using Microsoft.EntityFrameworkCore;
using System.ComponentModel.DataAnnotations;

public class Author
{
    public int AuthorId { get; set; }
    public string Name { get; set; } = "";
    public string Email { get; set; } = "";
    public List<Post> Posts { get; set; } = new();
}

public class Post
{
    public int PostId { get; set; }
    public string Title { get; set; } = "";
    public string Content { get; set; } = "";
    public DateTime PublishedAt { get; set; }

    public int AuthorId { get; set; }
    public Author Author { get; set; } = null!;
}

public class BlogContext : DbContext
{
    public DbSet<Author> Authors => Set<Author>();
    public DbSet<Post> Posts => Set<Post>();

    public BlogContext(DbContextOptions<BlogContext> options) : base(options) { }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Post>()
            .HasIndex(p => p.PublishedAt);

        modelBuilder.Entity<Author>()
            .HasIndex(a => a.Email).IsUnique();
    }
}

// Usage
var options = new DbContextOptionsBuilder<BlogContext>()
    .UseSqlite("Data Source=blog.db")
    .Options;

using (var db = new BlogContext(options))
{
    db.Database.EnsureCreated();

    var author = new Author { Name = "Jane Doe", Email = "jane@example.com" };
    db.Authors.Add(author);
    db.SaveChanges();

    var post = new Post
    {
        Title = "Getting Started with EF Core",
        Content = "Entity Framework Core is amazing...",
        PublishedAt = DateTime.UtcNow,
        AuthorId = author.AuthorId
    };
    db.Posts.Add(post);
    db.SaveChanges();
}

using (var db = new BlogContext(options))
{
    var posts = db.Posts
        .Include(p => p.Author)
        .Where(p => p.PublishedAt > DateTime.UtcNow.AddDays(-7))
        .OrderByDescending(p => p.PublishedAt)
        .ToList();

    foreach (var p in posts)
    {
        Console.WriteLine($"{p.Title} by {p.Author.Name} on {p.PublishedAt:d}");
    }
}

Output:

Getting Started with EF Core by Jane Doe on 6/28/2026

Entity Framework Core transforms database access in C# applications. With LINQ queries, automatic migrations, and change tracking, it is the standard data access technology for modern .NET applications.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro