Entity Framework Core Concepts
Entity Framework Core (EF Core) is a modern, cross-platform Object-Relational Mapper (ORM) for .NET. It enables developers to work with a database using .NET objects that represent the data, eliminating the need for most of the data-access code they typically need to write.
DbContext
The DbContext
is the primary class for interacting with Entity Framework Core. It represents a session with the database and allows you to query and save data. It's a gateway to your data. You typically create a class that derives from DbContext
and adds DbSet<TEntity>
properties for each entity in your model.
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=MyDatabase;Trusted_Connection=True;");
}
}
Entity Model
The entity model defines the shape of your data. It's composed of:
- Entities: Plain Old CLR Objects (POCOs) that represent tables in your database.
- Properties: Represent columns in your database tables.
- Relationships: Define how entities are related to each other (e.g., one-to-many, many-to-many).
EF Core can discover your entity model through conventions or by explicit configuration using Data Annotations or the Fluent API.
DbSet
A DbSet<TEntity>
property on your DbContext
represents a collection of all entities of a given type in the context, or that can be queried from the database. DbSet
is the primary way to query entities from the database.
using (var context = new BloggingContext())
{
var blogs = context.Blogs.ToList(); // Query all blogs
}
Migrations
Migrations are a feature of EF Core that allows you to incrementally update your database schema to match your evolving entity model without having to manually write and manage database scripts. They are managed through the .NET CLI or Package Manager Console.
Key migration commands:
dotnet ef migrations add InitialCreate
: Creates a new migration.dotnet ef database update
: Applies pending migrations to the database.
Querying
EF Core translates LINQ queries written against your DbSet
properties into SQL queries that are executed against the database. This allows you to query your data using familiar C# syntax.
using (var context = new BloggingContext())
{
var posts = context.Posts
.Where(p => p.Title.Contains("EF Core"))
.OrderBy(p => p.PublishedDate)
.ToList();
}
EF Core supports eager loading, explicit loading, and lazy loading of related data.
Change Tracking
EF Core automatically tracks changes made to entities that are retrieved from the database through the DbContext
. When you call SaveChanges()
, EF Core compares the current state of the tracked entities with their original state and generates the appropriate SQL commands (INSERT, UPDATE, DELETE) to synchronize the database.
using (var context = new BloggingContext())
{
var blogToUpdate = context.Blogs.Find(1);
if (blogToUpdate != null)
{
blogToUpdate.Url = "https://new-url.com";
context.SaveChanges(); // EF Core detects the change and issues an UPDATE
}
}
Relationships
EF Core supports various types of relationships between entities:
- One-to-One: A single instance of an entity is related to a single instance of another entity.
- One-to-Many: A single instance of an entity can be related to multiple instances of another entity.
- Many-to-Many: Multiple instances of an entity can be related to multiple instances of another entity.
These relationships are typically defined using navigation properties and configured using Fluent API or Data Annotations.

Conceptual diagram of entity relationships in EF Core.
Saving Changes
The DbContext.SaveChanges()
method is used to persist any changes made to tracked entities to the database. EF Core analyzes the state of all tracked entities and generates the necessary SQL commands. The SaveChangesAsync()
method provides an asynchronous alternative.
using (var context = new BloggingContext())
{
var newBlog = new Blog { Url = "https://example.com" };
context.Blogs.Add(newBlog);
var post = context.Posts.Find(5);
if (post != null)
{
post.Content = "Updated content.";
}
context.SaveChanges(); // Persists both the new blog and the updated post
}