Entity Framework (EF6 & EF Core)
What it is & where it is used
Entity Framework Core (EF Core) is Microsoft's open-source ORM (Object-Relational Mapper) for .NET. You work with C# classes (entities) and LINQ; EF Core generates SQL, tracks changes and maps results back to objects.
Supported databases (providers): SQL Server / Azure SQL, SQLite, PostgreSQL (Npgsql), MySQL/MariaDB (Pomelo), Oracle, Cosmos DB, In-Memory (testing only).
Workflows:
- Code-first — write entity classes, generate the schema with migrations (most common for new apps).
- Database-first — scaffold classes from an existing DB (
dotnet ef dbcontext scaffold).
EF6 (Entity Framework 6) is the older .NET Framework ORM, now in maintenance; EF Core is the modern rewrite (and EF6 also runs on .NET Core 3.1+ for migration scenarios).
Versions & history
| Version | Year | Highlights |
|---|---|---|
| EF 1.0 → EF 6 | 2008 → 2013 | .NET Framework ORM; EDMX designer, Code First (4.1), migrations (4.3) |
| EF Core 1.0 | 2016 | Rewrite, lightweight, cross-platform |
| EF Core 2.0/2.1 | 2017/2018 | Global query filters, owned types, lazy loading proxies, value conversions |
| EF Core 3.0/3.1 (LTS) | 2019 | LINQ overhaul — no more silent client evaluation |
| EF Core 5 | 2020 | Many-to-many without join entity, split queries, filtered Include, ToQueryString() |
| EF Core 6 (LTS) | 2021 | Temporal tables, compiled models, migration bundles, pre-convention config |
| EF Core 7 | 2022 | ExecuteUpdate/ExecuteDelete (bulk), JSON columns, TPC mapping |
| EF Core 8 (LTS) | 2023 | Complex types (value objects), primitive collections, raw SQL for unmapped types, HierarchyId |
| EF Core 9 | 2024 | Better Cosmos DB, auto-compiled models for AOT (experimental), UseSeeding |
| EF Core 10 (LTS) | 2025 | Ships with .NET 10: named query filters, LeftJoin/RightJoin translation, vector search for SQL Server, complex types improvements |
EF Core majors follow .NET's yearly November releases and support policy (even = LTS).
Lifecycle
DbContext lifecycle (ASP.NET Core): registered scoped → one instance per HTTP request → created via DI → used for queries and changes → SaveChanges() → disposed at the end of the request. A DbContext is a unit of work, not thread-safe, and meant to be short-lived.
Entity states (change tracking):
| State | Meaning | On SaveChanges |
|---|---|---|
Detached | Not tracked | nothing |
Added | New, Add() called | INSERT |
Unchanged | Loaded, not modified | nothing |
Modified | Property changed | UPDATE (changed columns) |
Deleted | Remove() called | DELETE |
Query lifecycle: LINQ → expression tree → EF query pipeline (translation, cached compiled query) → SQL → DbDataReader → materialise entities → identity resolution (one instance per key per context) → tracked as Unchanged (unless AsNoTracking).
SaveChanges lifecycle: DetectChanges() (snapshot comparison) → order commands by dependencies → begin transaction (implicit) → batch INSERT/UPDATE/DELETE → read back generated values (identity, rowversion) → commit → states become Unchanged.
Migration lifecycle: change model → dotnet ef migrations add Name (generates Up/Down C#) → review → dotnet ef database update in dev → in prod apply via SQL script (migrations script --idempotent) or migration bundle in CI/CD.
Tools used to develop
| Tool | Use |
|---|---|
dotnet-ef CLI (dotnet tool install --global dotnet-ef) | migrations, scaffold, bundles, dbcontext optimize |
| Package Manager Console (VS) | Add-Migration, Update-Database, Scaffold-DbContext |
| EF Core Power Tools (VS extension) | Reverse engineer, diagram the model |
| SQL Server Profiler / Extended Events / Query Store | See and tune generated SQL |
LogTo, EnableSensitiveDataLogging (dev), ToQueryString() | Debug queries |
| MiniProfiler, Application Insights | Query timing in apps |
| EFCore.BulkExtensions, Z.EntityFramework.Extensions | Third-party bulk operations |
| Testcontainers, SQLite | Integration tests |