EF Core需模型定义、上下文配置和迁移三者齐全,否则SaveChanges()静默失败或抛InvalidOperationException;DbContext必须显式配置数据库提供程序,否则报“No database provider has been configured”。

EF Core 不是“装完包就能查数据”的工具,缺模型定义、上下文配置、迁移三者中任一环,SaveChanges() 就会静默失败或直接抛 InvalidOperationException。
DbContext 必须显式配数据库提供程序,否则报“No database provider has been configured”
只写 public class AppDbContext : DbContext 是无效的。EF Core 完全不知道连哪、用哪种数据库。
- 本地快速验证:重写
OnConfiguring,调用optionsBuilder.UseSqlite("Data Source=app.db")或UseSqlServer(...) - 生产环境必须走依赖注入 +
appsettings.json:避免硬编码,也方便切换环境(比如开发用 SQLite,测试用 SQL Server) - SQLite 路径别写死:
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData)比C:\temp\app.db更可靠,尤其在非管理员账户下
实体类主键不合规,迁移会成功但建表失败
dotnet ef migrations add 可能通过,但 dotnet ef database update 会在执行 SQL 时卡住——因为生成的 CREATE TABLE 语句里没 PRIMARY KEY。
- EF Core 默认只认
Id或BlogId(类名+Id)这类命名,且类型要是int、long或Guid -
public int blog_id { get; set; }不会被识别为主键;public string Id { get; set; }也不行(类型不对) - 强制指定主键:加
[Key]特性,或在OnModelCreating里用 Fluent API 写modelBuilder.Entity<Blog>().HasKey(e => e.BlogId)
SaveChangesAsync() 不是可选步骤,而是写库的唯一开关
Add()、Update()、Remove() 都只是改 EF 内部状态标记,不发任何 SQL。没调 SaveChangesAsync(),等于什么都没做。
- Web 场景:用 DI 注册
AppDbContext,生命周期设为Scoped,控制器里构造函数接收,别自己new - 控制台/脚本场景:必须用
using var ctx = new AppDbContext(options);包裹操作,确保Dispose()被调用 - 绝对禁止:静态字段存
DbContext、注册为Singleton、或在循环里反复new—— 会触发A second operation started on this context before a previous operation completed
IQueryable 查询条件必须下推到 SQL 层,否则性能崩盘
过早调用 ToList() 会让整张表拉进内存再过滤,失去索引、分页、聚合能力。
- 错误写法:
context.Users.ToList().Where(u => u.Status == "Active")→ 全表加载 - 正确写法:
await context.Users.Where(u => u.Status == "Active").ToListAsync()→WHERE下推 - 分页必须服务端做:
context.Users.Skip(100).Take(20),不是.ToList().Skip().Take() - 总数统计用
CountAsync(),不是.ToList().Count
最常被忽略的其实是迁移文件的边界:每次 dotnet ef database update 只执行**最后一次迁移的 Up() 方法**,不是所有迁移叠加执行;删掉迁移文件夹再重新 add,也不会清空已有数据库结构。


















