一、什么是 DbContext?
DbContext
是 EF Core 中非常核心的类,它充当了数据库操作的桥梁,是数据库交互的主要入口。它负责管理与数据库的连接、事务、查询、更新等操作。
简单来说,DbContext
的作用可以总结为:
负责管理实体(即应用程序中的对象)与数据库表之间的映射。 提供用于与数据库交互的方法,如 Add
、Update
、Remove
、SaveChanges
等。管理数据库的连接和事务。
二、DbContext 的工作原理
1. 数据库连接
每个 DbContext
实例都有一个数据库连接,它会在需要时自动打开和关闭连接。DbContext
通过 Database
属性与数据库进行连接。
示例代码:
using var context = new MyDbContext();
var users = context.Users.ToList(); // 数据库连接会自动打开
2. 实体映射
DbContext
负责将实体类与数据库表进行映射,确保从数据库中读取到的数据能被正确地转换为实体对象,或者将实体对象的状态变更(如新增、更新、删除)映射成对应的 SQL 命令。
- 实体类到数据库表的映射
:通过 DbSet<TEntity>
来表示表。 - 属性到列的映射
:EF Core 会根据约定、数据注解或 Fluent API 来推断实体类的属性与数据库列的关系。
示例代码:
public class MyDbContext : DbContext
{
public DbSet<User> Users { get; set; } 映射 Users 表
}
3. 变更追踪(Change Tracking)
DbContext
会追踪实体对象的状态(如 Added
、Modified
、Deleted
)。当你对一个实体做出更改时,DbContext
会记录这些更改,并在调用 SaveChanges()
时自动生成 SQL 命令来将这些更改应用到数据库中。
变更追踪的三种状态:
- Added
:新增的实体。 - Modified
:已经修改的实体。 - Deleted
:被删除的实体。 - Unchanged
:未修改的实体。
示例代码:
using var context = new MyDbContext();
var user = new User { Name = "李四" };
context.Users.Add(user); // 变更状态为 Added
context.SaveChanges(); // 将新增数据保存到数据库
4. SaveChanges() 的执行流程
SaveChanges()
是 DbContext
中非常关键的一个方法,负责:
将所有变更(插入、更新、删除)转化为相应的 SQL 命令。 执行 SQL 命令并将更改持久化到数据库。
在调用 SaveChanges()
时:
EF Core 会遍历 DbContext
中所有的实体,检查它们的状态。根据实体的状态生成相应的 SQL 命令。 通过事务确保数据一致性。
示例代码:
context.Users.Add(new User { Name = "王五" });
context.SaveChanges(); // 生成 INSERT SQL 并执行
5. 数据库上下文生命周期
每次你创建 DbContext
实例时,它会开启一个新的数据库连接和事务。当 DbContext
被销毁时,它会自动关闭连接。
通常,DbContext
是短生命周期的对象。它在请求的范围内创建并使用,当请求完成时销毁。这样可以确保在操作完成后及时释放资源。
示例代码:
// 推荐做法:每次请求创建新的 DbContext
using var context = new MyDbContext();
context.Users.Add(new User { Name = "赵六" });
context.SaveChanges();
6. 事务管理
如前所述,DbContext
会自动处理事务。如果在 SaveChanges()
中执行了多个 SQL 命令,这些命令会在同一个事务中执行,保证操作的原子性。
你也可以手动控制事务,通过 BeginTransaction
启动一个事务,使用 Commit
提交事务,或者在出错时通过 Rollback
回滚事务。
示例代码:
using var context = new MyDbContext();
using var transaction = context.Database.BeginTransaction();
try
{
context.Users.Add(new User { Name = "孙七" });
context.SaveChanges();
transaction.Commit(); // 提交事务
}
catch
{
transaction.Rollback(); // 回滚事务
}
三、DbContext 与多线程
DbContext
是线程不安全的,因此每个线程(如每个 HTTP 请求)都应该使用一个独立的 DbContext
实例。如果在多线程环境中共享同一个 DbContext
,可能会导致不可预知的错误。
四、总结
关键点 | 描述 |
数据库连接 |
会管理与数据库的连接,并自动打开/关闭 |
实体映射 |
通过 映射实体与数据库表 |
变更追踪 |
会自动追踪实体的增、删、改操作 |
SaveChanges() |
会生成 SQL 并执行,将更改持久化到数据库 |
事务管理 |
会自动管理事务,确保数据一致性 |
生命周期 |
通常是短生命周期对象,每个请求一个实例 |




