.NET Entity Framework (EF) Core 完整教程
目录
- 什么是 EF Core?
- 为什么使用 EF Core?
- 核心概念
- 环境准备
- 实战教程:创建第一个 EF Core 应用
- 步骤 1:创建项目
- 步骤 2:安装 EF Core NuGet 包
- 步骤 3:定义模型类
- 步骤 4:创建数据库上下文
- 步骤 5:配置数据库连接字符串
- 步骤 6:使用 Code First 创建数据库
- 步骤 7:进行 CRUD 操作
- 进阶主题
- 学习资源与最佳实践
什么是 EF Core?
Entity Framework (EF) Core 是微软官方的开源、跨平台、轻量级的 对象关系映射器。

它是一个数据访问技术,能够让你:
- 用 C# 对象(模型类)来操作数据库,而不是手写复杂的 SQL 语句。
- 自动将 C# 对象映射到数据库表,将对象的属性映射到表的列。
- 将数据库查询的结果自动转换回 C# 对象。
你可以把它想象成一个“翻译官”,在你的 C# 代码和 SQL 数据库之间进行沟通。
重要提示:我们现在通常说的 EF Core,是 EF 的重大重构版本,专门为 .NET Core 和 .NET 5+ 设计,性能更好,更现代化。
为什么使用 EF Core?
- 提高开发效率:无需编写、维护和调试大量重复的 SQL 代码,专注于业务逻辑。
- 代码可读性和可维护性:C# 代码比 SQL 语句更易于阅读和维护。
- 减少错误:自动化的映射和查询减少了手写 SQL 可能带来的错误。
- 数据库无关性:你可以通过更换数据库提供程序,轻松地将应用程序从 SQL Server 切换到 PostgreSQL、SQLite、MySQL 等,而无需修改业务逻辑代码。
- 强大的功能:支持 LINQ 查询、变更跟踪、迁移、异步操作等高级特性。
核心概念
在学习使用之前,必须理解以下几个核心概念:

| 概念 | 解释 | 类比 |
|---|---|---|
| 模型 | 一个普通的 C# 类(POCO),通常用 [Table] 和 [Column] 等特性来标注,代表数据库中的一张表。 |
设计图纸(表的结构) |
| 数据库上下文 | 继承自 DbContext 的类,是 EF Core 的核心,它负责连接数据库,并包含 DbSet<T> 属性来表示模型对应的数据库表。 |
施工队(负责按图纸盖房子) |
| DbSet | 在 DbContext 中定义的属性,类型为 DbSet<T>,T 是你的模型类,它代表数据库中的一个表,并提供了对数据进行增删改查的方法(如 Add(), Remove(), Find(), ToList())。 |
施工队手中的工具箱(操作表的方法) |
| 迁移 | EF Core 的一项功能,用于将你的模型类(代码)的变更同步到数据库结构中,它会自动生成创建/修改表的 SQL 脚本并执行。 | 版本控制系统(Git),记录数据库结构的变更历史 |
| LINQ | 语言集成查询,一种在 C# 中编写查询的强大语法,EF Core 会将 LINQ 查询表达式翻译成相应的 SQL 语句发送给数据库。 | 用自然语言向施工队下达指令(“给我找所有红色的砖”) |
环境准备
- 安装 .NET SDK:从 .NET 官网 下载并安装最新的 .NET SDK。
- 选择一个 IDE:
- Visual Studio 2025 (推荐,社区版免费):安装时请勾选 “.NET 桌面开发” 或 “ASP.NET 和 Web 开发” 工作负载。
- Visual Studio Code:配合 C# Dev Kit 扩展使用,非常轻量。
- 选择一个数据库:为了简单起见,我们本教程使用 SQLite,它是一个轻量级的文件数据库,无需安装服务器,非常适合学习和本地开发。
实战教程:创建第一个 EF Core 应用
我们将创建一个控制台应用程序,管理一个简单的“博客”系统,包含 Blog 和 Post 两个实体。
步骤 1:创建项目
打开终端或命令提示符,运行以下命令:
# 创建一个新的控制台应用 dotnet new console -n EfCoreDemo # 进入项目目录 cd EfCoreDemo
步骤 2:安装 EF Core NuGet 包
我们需要安装 EF Core 核心包和 SQLite 提供程序包。
# 安装 EF Core 核心包 dotnet add package Microsoft.EntityFrameworkCore # 安装 SQLite 提供程序包 dotnet add package Microsoft.EntityFrameworkCore.Sqlite
步骤 3:定义模型类
在项目中创建一个名为 Models 的文件夹,并在其中创建两个类:Blog.cs 和 Post.cs。
Models/Blog.cs
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
namespace EfCoreDemo.Models
{
// [Table("Blogs")] // 可选,如果不指定,表名默认为类名
public class Blog
{
public int BlogId { get; set; } // 默认为主键
[Required] // 数据库列不能为空
[StringLength(100)] // 字符串最大长度为100
public string Url { get; set; }
// 一个博客可以有多篇博文
public List<Post> Posts { get; set; }
}
}
Models/Post.cs
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace EfCoreDemo.Models
{
public class Post
{
public int PostId { get; set; }
[Required]
public string Title { get; set; }
public string Content { get; set; }
// 外键,指向 Blog 表的 BlogId
public int BlogId { get; set; }
// 导航属性,一篇博文属于一个博客
[ForeignKey("BlogId")]
public Blog Blog { get; set; }
}
}
步骤 4:创建数据库上下文
创建一个名为 Data 的文件夹,并在其中创建 BloggingDbContext.cs 文件。
Data/BloggingDbContext.cs
using Microsoft.EntityFrameworkCore;
using EfCoreDemo.Models;
namespace EfCoreDemo.Data
{
public class BloggingDbContext : DbContext
{
// 这个构造函数是必需的,用于将配置选项(如连接字符串)传递给 DbContext
public BloggingDbContext(DbContextOptions<BloggingDbContext> options) : base(options)
{
}
// DbSet 属性代表数据库中的表
public DbSet<Blog> Blogs { get; set; }
public DbSet<Post> Posts { get; set; }
}
}
步骤 5:配置数据库连接字符串
打开 Program.cs 文件,我们将在这里配置应用和数据库上下文。
Program.cs
using Microsoft.EntityFrameworkCore;
using EfCoreDemo.Data;
using System.Linq;
// 1. 配置数据库连接字符串并创建 DbContext 实例
// 使用 SQLite 内存数据库,数据只存在于程序运行期间
var connectionString = "Data Source=:memory:";
var optionsBuilder = new DbContextOptionsBuilder<BloggingDbContext>();
optionsBuilder.UseSqlite(connectionString);
using var dbContext = new BloggingDbContext(optionsBuilder.Options);
// 2. 确保数据库被创建
// 如果数据库不存在,此方法会根据模型创建它
dbContext.Database.EnsureCreated();
Console.WriteLine("数据库已创建!");
// ... 接下来我们将在这里进行 CRUD 操作 ...
步骤 6:使用 Code First 创建数据库
在上一步的 Program.cs 中,我们已经调用了 dbContext.Database.EnsureCreated(),这行代码会检查数据库是否存在,如果不存在,就会根据我们定义的 Blog 和 Post 模型自动创建 Blogs 和 Posts 表。
你可以运行程序试试看,虽然不会有输出,但数据库(在内存中)确实已经被创建了。
步骤 7:进行 CRUD 操作
我们向 Program.cs 的 using 代码块中添加具体的增删改查操作。
完整的 Program.cs
using Microsoft.EntityFrameworkCore;
using EfCoreDemo.Data;
using EfCoreDemo.Models;
using System.Linq;
// 1. 配置数据库连接字符串并创建 DbContext 实例
var connectionString = "Data Source=:memory:";
var optionsBuilder = new DbContextOptionsBuilder<BloggingDbContext>();
optionsBuilder.UseSqlite(connectionString);
using var dbContext = new BloggingDbContext(optionsBuilder.Options);
// 2. 确保数据库被创建
dbContext.Database.EnsureCreated();
Console.WriteLine("数据库已创建!");
// ============ C - Create (创建) ============
Console.WriteLine("\n--- 创建博客 ---");
var blog = new Blog { Url = "https://example.com" };
dbContext.Blogs.Add(blog); // 将新博客添加到 DbSet
dbContext.SaveChanges(); // 保存更改到数据库
Console.WriteLine($"已创建博客,ID: {blog.BlogId}");
// ============ R - Read (查询) ============
Console.WriteLine("\n--- 查询所有博客 ---");
var allBlogs = dbContext.Blogs.ToList(); // 将查询结果转换为 List
foreach (var b in allBlogs)
{
Console.WriteLine($"博客 ID: {b.BlogId}, URL: {b.Url}");
}
// ============ U - Update (更新) ============
Console.WriteLine("\n--- 更新博客 URL ---");
var blogToUpdate = dbContext.Blogs.FirstOrDefault(b => b.BlogId == 1);
if (blogToUpdate != null)
{
blogToUpdate.Url = "https://updated-example.com";
dbContext.SaveChanges(); // 再次保存更改
Console.WriteLine($"已更新博客 ID {blogToUpdate.BlogId} 的 URL 为 {blogToUpdate.Url}");
}
// ============ D - Delete (删除) ============
Console.WriteLine("\n--- 删除博客 ---");
var blogToDelete = dbContext.Blogs.FirstOrDefault(b => b.BlogId == 1);
if (blogToDelete != null)
{
dbContext.Blogs.Remove(blogToDelete); // 从 DbSet 中移除
dbContext.SaveChanges(); // 保存更改
Console.WriteLine($"已删除博客 ID {blogToDelete.BlogId}");
}
Console.WriteLine("\n--- 再次查询所有博客 ---");
var remainingBlogs = dbContext.Blogs.ToList();
if (!remainingBlogs.Any())
{
Console.WriteLine("数据库中没有博客了。");
}
运行程序,你将在控制台看到完整的输出,清晰地展示了数据库的创建和数据的增删改查过程。
进阶主题
当你掌握了基础后,可以继续学习以下内容:
- 数据库迁移:使用
dotnet ef命令行工具来管理数据库结构的版本,这是生产环境中的标准做法。dotnet ef migrations add MyNewMigration- 创建一个新的迁移。dotnet ef database update- 将迁移应用到数据库。
- 关系配置:使用 Fluent API 在
DbContext的OnModelCreating方法中更灵活地配置实体间的关系(一对一、一对多、多对多)。 - 查询:深入学习 LINQ to Entities,包括过滤、排序、分组、聚合函数等。
- 异步操作:使用
async和await关键字执行数据库操作,以避免阻塞 UI 线程(尤其在桌面和 Web 应用中至关重要)。await dbContext.Blogs.ToListAsync();
- 并发控制:处理多个用户同时修改同一数据时可能发生的冲突。
- 存储过程:如何调用数据库中的存储过程。
学习资源与最佳实践
官方文档
- EF Core 官方文档:这是最权威、最全面的学习资源,没有之一。
视频教程
- Phillip Japikse 的 Pluralsight 课程:非常经典和深入。
- FreeCodeCamp 的 YouTube 视频:免费且内容质量高。
- Bilibili:搜索 “.NET EF Core” 或 “Entity Framework Core”,有大量国内博主制作的优秀教程。
最佳实践
- 不要在
DbContext中放置业务逻辑:DbContext应该只负责数据访问。 - 使用仓储模式:对于大型项目,可以使用仓储模式来封装数据访问逻辑,使代码更解耦。
- 谨慎使用
AsNoTracking():对于只读查询,使用AsNoTracking()可以显著提高性能,因为它会禁用 EF Core 的变更跟踪功能。 - 依赖注入:在现代 .NET 应用中,始终通过依赖注入来使用
DbContext,而不是在类中new一个实例。 - 保持模型简单:模型类应尽量保持“贫血”(Anemic),即只包含数据属性和行为,复杂的业务逻辑应放在服务层。
希望这份详细的教程能帮助你顺利入门 .NET EF Core!祝你学习愉快!
