什么是 `DbContext`
1 min read
DbContext
可以理解为 你和数据库的桥梁,每次你要操作数据库时,都会开启一个 "会话"(session),这个会话就是 DbContext
的实例。你可以用它来查询数据、添加数据、更新数据、删除数据。
DbContext
用了两种设计模式
- Unit of Work(工作单元模式) 👉 把多个数据库操作打包成一个事务,确保它们要么全部成功,要么全部失败,避免数据不一致。
- Repository(仓储模式) 👉 让你可以用对象(C# 类)来操作数据库,而不需要直接写 SQL。
为什么 DbContext
不能被多个线程同时使用?
简单来说:一个
DbContext
实例不能同时被多个地方用,尤其是并发执行的异步任务!
DbContext
内部有状态,如果多个线程同时修改它,就可能导致数据混乱,甚至程序崩溃。- 异步查询必须用
await
,这样能确保查询完成后再执行下一步,不会产生并发问题。 - 如果需要并发处理,应该创建多个
DbContext
实例,而不是让多个线程共用同一个实例。
✅ 正确示例(使用 await
,保证异步执行顺序):
1
var users = await context.Users.ToListAsync(); // 先执行查询,等它完成后再执行下一步
❌ 错误示例(多个线程同时访问同一个 DbContext
,可能会崩溃):
1 2 3
var task1 = context.Users.ToListAsync(); // 开始查询 var task2 = context.Orders.ToListAsync(); // 同时开始查询订单 await Task.WhenAll(task1, task2); // 并发执行(可能会出问题)
⚠ 解决方案:给 task2
用新的 DbContext
实例!
如何定义 DbContext
?
通常,我们需要创建一个 继承自 DbContext
的类,并在里面定义 DbSet
(表示数据库表)。
示例:
1 2 3 4 5
public class AppDbContext : DbContext { public DbSet<User> Users { get; set; } // Users 表 public DbSet<Order> Orders { get; set; } // Orders 表 }
⚡ 注意:如果 DbSet
有 public
的 set
,DbContext
创建时会自动初始化这些 DbSet
,你就可以直接使用它们查询数据库!
总结
DbContext
是你和数据库的桥梁,用来查询、保存数据。- 它结合了 "工作单元" 和 "仓储模式",简化数据库操作。
- 不能在多个线程中同时使用同一个
DbContext
实例,否则会出错! - 异步查询必须
await
,并发操作要用不同的DbContext
实例。 DbContext
里通常有DbSet
,每个DbSet
代表数据库中的一张表。