EFCore 的 DbContext 必须通过 AddDbContext 以 Scoped 生命周期注册到 DI 容器,禁用 OnConfiguring,构造函数注入 DbContextOptions,只读查询加 AsNoTracking(),迁移需指定启动项目,批量更新优先用 ExecuteUpdateAsync。

EFCore 的 DbContext 怎么注册到 DI 容器里
不注册就 new 实例,迟早出线程安全和生命周期问题。ASP.NET Core 默认用 Scoped 生命周期,DbContext 必须这么配,否则可能拿到过期连接或并发写冲突。
-
AddDbContext是唯一推荐方式,别手写new AppDbContext() - 连接字符串必须从配置读,别硬编码——
Configuration.GetConnectionString("Default") - SQL Server 用
Microsoft.EntityFrameworkCore.SqlServer包,PostgreSQL 则换Npgsql.EntityFrameworkCore.PostgreSQL - 开发阶段加
.EnableSensitiveDataLogging()能看 SQL,但上线前务必关掉
示例(Program.cs):
builder.Services.AddDbContext<appdbcontext>(options =>
options.UseSqlServer(builder.Configuration.GetConnectionString("Default")))</appdbcontext>
AppDbContext 类要怎么写才不出错
基类继承、OnConfiguring 和 OnModelCreating 三者关系容易搞混:只要用了 DI 注册,OnConfiguring 就该留空或直接删掉,否则会覆盖 DI 传入的 options。
- 构造函数必须带
DbContextOptions参数,并传给 base - 每个
DbSet属性名最好和表名一致,避免后续映射混乱 - 别在
OnModelCreating里重复配置主键或外键——如果实体用了[Key]或[ForeignKey],EFCore 通常能自动推导 - 想禁用级联删除?在
OnModelCreating里写:modelBuilder.Entity().HasOne(x => x.User).WithMany().OnDelete(DeleteBehavior.Restrict)
典型骨架:
public class AppDbContext : DbContext
{
public AppDbContext(DbContextOptions<appdbcontext> options) : base(options) { }
public DbSet<user> Users { get; set; }
public DbSet<order> Orders { get; set; }
}</order></user></appdbcontext>
迁移命令跑不起来,常见卡点在哪
不是“没装工具”,而是环境没对齐。EFCore 迁移依赖设计时上下文实例,而 CLI 工具默认找启动项目里的 DbContext,如果上下文在类库,就得指定启动项目。
- 确保已安装
dotnet-ef全局工具:dotnet tool install --global dotnet-ef - 在含
DbContext的项目目录下执行命令,否则报Unable to create an object of type 'AppDbContext' - 生成迁移:用
dotnet ef migrations add Init,不是add-migration(那是旧版 PowerShell 命令) - 应用迁移:用
dotnet ef database update,不是update-database - 若提示找不到
IDesignTimeDbContextFactory,说明 CLI 找不到如何构造上下文——此时要么把上下文所在项目设为启动项,要么手动实现工厂接口
查询时突然报“无法跟踪实体”,怎么解
这是 EFCore 默认开启变更追踪惹的祸。查完立刻改对象,又没 AsNoTracking(),EFCore 就会试图跟踪它;但若上下文已释放或跨作用域,就崩出 InvalidOperationException: The instance of entity type 'X' cannot be tracked。
- 只读查询一律加
.AsNoTracking(),性能更好,也避坑 - 需要更新再查,用
.FindAsync(id)或.SingleAsync(x => x.Id == id),它们天然支持跟踪 - 别在 View 层或 DTO 映射里调
.ToList()后再改实体属性——跟踪状态已丢失 - 批量更新不用 EFCore 查再改,直接上
ExecuteUpdateAsync(EFCore 7+)或原始 SQL
反例(危险):
var user = await context.Users.FirstAsync(); user.Name = "new"; // 此时 context 可能已 disposed await context.SaveChangesAsync(); // ?
EFCore 的坑大多藏在生命周期和查询模式里,而不是语法本身。很多人调通第一行 SaveChanges 就以为搞定了,其实真正麻烦的是并发请求下上下文复用、热重载时迁移失败、还有查询后意外修改导致的跟踪异常——这些不跑一段时间压根不会暴露。











