Data Access with Entity Framework Core
Table of Contents
Introduction to EF Core
Entity Framework Core (EF Core) is a modern, lightweight, cross-platform, and extensible object-relational mapper (ORM) for .NET. It enables .NET developers to work with a database using domain-specific objects that are essentially ADO.NET entity types. EF Core is a complete rewrite of the popular Entity Framework 6, with significant architectural improvements and performance enhancements.
EF Core provides a convenient way to:
- Map .NET objects to database tables.
- Persist these objects to the database.
- Query data from the database using LINQ (Language Integrated Query).
- Manage database schema changes using migrations.
Installation
You can install EF Core and its providers via NuGet packages. The most common provider is for SQL Server.
dotnet add package Microsoft.EntityFrameworkCore
dotnet add package Microsoft.EntityFrameworkCore.SqlServer
dotnet add package Microsoft.EntityFrameworkCore.Tools
Microsoft.EntityFrameworkCore.Tools
is essential for working with migrations from the command line.
Creating a Model
EF Core uses Plain Old CLR Objects (POCOs) to represent your database schema. These are simple classes with properties that map to columns in your database tables.
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
public string Rating { 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 Blog Blog { get; set; }
}
EF Core follows certain conventions for discovering entity types and their relationships. For example, properties named `Id` or `[EntityName]Id` are typically recognized as primary keys.
Setting up the DbContext
The DbContext
class is the entry point for interacting with your EF Core model and database. It represents a session around a database, allowing you to query and save data.
using Microsoft.EntityFrameworkCore;
public class BloggingContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
public DbSet<Post> Posts { get; set; }
public BloggingContext(DbContextOptions<BloggingContext> options)
: base(options)
{
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
// Configure relationships or other model details here
modelBuilder.Entity<Blog>()
.Property(b => b.Url)
.IsRequired();
}
// Optional: Configure the database connection string directly if not using DI
// protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
// {
// optionsBuilder.UseSqlServer("Server=(localdb)\\mssqllocaldb;Database=BloggingEFCore;Trusted_Connection=True;");
// }
}
In a modern ASP.NET Core application, you'll typically configure the DbContext
using Dependency Injection (DI) in your Startup.cs
or Program.cs
file.
Migrations
Migrations allow you to evolve your database schema over time as your application model changes. EF Core Migrations can:
- Create new tables, columns, and constraints based on your model.
- Apply changes to an existing database.
- Generate SQL scripts for manual deployment.
To add a new migration:
dotnet ef migrations add InitialCreate
This command will generate a new folder named Migrations
containing code that describes the changes to be applied to your database. To apply the migration to your database:
dotnet ef database update
Microsoft.EntityFrameworkCore.Tools
NuGet package and that your startup project is correctly configured for the `dotnet ef` commands to find your `DbContext`.
Querying Data
You can use LINQ to query data from your database through your DbContext
.
using (var context = new BloggingContext(options)) // Assuming options are configured
{
// Get all blogs
var blogs = context.Blogs.ToList();
// Get blogs with a specific URL
var specificBlog = context.Blogs.FirstOrDefault(b => b.Url.Contains("microsoft"));
// Include related data (e.g., posts for each blog)
var blogsWithPosts = context.Blogs.Include(b => b.Posts).ToList();
// Filter and order posts
var recentPosts = context.Posts
.Where(p => p.Blog.Url == "example.com")
.OrderByDescending(p => p.PostId)
.ToList();
}
EF Core translates these LINQ queries into SQL statements that are executed against the database.
Saving Data
Adding, updating, and deleting entities involves modifying the state of entities tracked by the DbContext
and then calling SaveChanges()
.
using (var context = new BloggingContext(options))
{
// Adding a new entity
var newBlog = new Blog { Url = "newblog.com", Rating = "Good" };
context.Blogs.Add(newBlog);
context.SaveChanges(); // Persists the new blog to the database
// Updating an existing entity
var blogToUpdate = context.Blogs.Find(1); // Or use FirstOrDefault
if (blogToUpdate != null)
{
blogToUpdate.Rating = "Excellent";
context.SaveChanges(); // Updates the blog in the database
}
// Deleting an entity
var blogToDelete = context.Blogs.FirstOrDefault(b => b.Url == "obsolete.com");
if (blogToDelete != null)
{
context.Blogs.Remove(blogToDelete);
context.SaveChanges(); // Deletes the blog from the database
}
}
SaveChanges()
, it generates and executes the necessary SQL commands to persist those changes.
Relationships
EF Core supports various relationships, including one-to-one, one-to-many, and many-to-many.
One-to-Many (Blog to Posts)
As shown in the model definition, a Blog
can have many Post
s, and each Post
belongs to one Blog
. The foreign key property BlogId
in the Post
class and the navigation property Blog
in Post
, and the collection Posts
in Blog
define this relationship.
Configuring Relationships
You can configure relationships explicitly in OnModelCreating
if EF Core's conventions don't match your needs.
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Post>()
.HasOne(p => p.Blog)
.WithMany(b => b.Posts)
.HasForeignKey(p => p.BlogId);
}
This explicitly defines the one-to-many relationship between Post
and Blog
.