Entity Framework Core 不是“先学再用”的框架,而是“边建模边理解”的工具。如果你刚创建完第一个
DbContext却发现查询返回空、迁移不生成表、或
SaveChanges()报错,说明你卡在了模型约定和生命周期这两个真实痛点上。
为什么 DbContext 实例不能全局单例?
EF Core 的
DbContext不是线程安全的,也不是轻量对象。它内部维护了变更跟踪器(
ChangeTracker)、缓存、以及当前连接状态。若在 ASP.NET Core 中注册为
Singleton,多个请求会共享同一实例,导致实体状态混乱、并发修改异常,甚至出现“An instance of entity type 'X' cannot be tracked”这类错误。 ASP.NET Core 中必须注册为
Scoped:
services.AddDbContext<AppDbContext>(options =>
options.UseSqlServer(connectionString));
手动 new 出来的 DbContext必须显式
Dispose(),尤其在非 Web 环境(如 Console 或 BackgroundService)中 不要在静态字段或单例服务里持有
DbContext实例
DbSet 查询返回空,但数据库明明有数据?
最常见原因是未正确配置主键或忽略大小写/类型匹配。EF Core 默认按命名约定推断主键:类名为
User,就找
Id或
UserId。如果实体是
public class user { public int id { get; set; } }(小写),EF Core 会认为没有主键,整个 DbSet<user></user>被跳过映射。 加
[Key]特性或在
OnModelCreating中显式配置:
modelBuilder.Entity<user>().HasKey(e => e.id);检查字段类型是否与数据库一致:C# 的
DateTime对应 SQL Server 的
datetime2,不是
datetime;
string默认映射为
nvarchar(max),若数据库是
varchar(50),需用
[Column(TypeName = "varchar(50)")]使用
context.Set<t>().AsNoTracking()</t>只读查询时,不会触发变更跟踪,但不影响数据读取——空结果通常不是因为它
add-migration 什么都不生成?
dotnet ef migrations add命令只对比当前模型与
Migrations目录下最后一个快照(
*.Designer.cs文件)。如果没生成任何代码,大概率是以下三种情况之一: 项目未安装
Microsoft.EntityFrameworkCore.Tools包,或未在
.csproj中启用设计时支持:
<PropertyGroup> <TargetFramework>net8.0</TargetFramework> <ImplicitUsings>enable</ImplicitUsings> <Nullable>enable</Nullable> <IsPackable>false</IsPackable> </PropertyGroup>上下文类未继承自
DbContext,或构造函数未接收
DbContextOptions<t></t>模型类未在
OnModelCreating或
DbSet<t></t>属性中被引用(例如漏写了
public DbSet<product> Products { get; set; }</product>)
SaveChanges() 报错 “Cannot insert explicit value for identity column”?
这是 EF Core 对自增主键(SQL Server 的
IDENTITY、PostgreSQL 的
SERIAL)的保护机制。当你给一个标识列赋了值(比如
new Product { Id = 100, Name = "A" }),EF Core 默认认为你想显式插入该值,而数据库不允许。
解决方法一:移除赋值,让数据库生成:var p = new Product { Name = "A" }; // 不设 Id
解决方法二:若真需要指定 ID(如迁移旧数据),需在模型中关闭值生成:modelBuilder.Entity<Product>()
.Property(e => e.Id)
.ValueGeneratedNever();
注意:MySQL 的 AUTO_INCREMENT列默认也受此规则约束,不能靠
HasDefaultValueSql("nextval('seq')") 绕过
EF Core 的“约定优于配置”省事,但也意味着出问题时很难一眼看出哪条约定被打破了。比起死记文档,更有效的方式是打开
DbContext的日志输出,看它实际生成的 SQL 和模型解析过程——那才是你真正该调试的地方。
