entity framework core 入门教程

来源:这里教程网 时间:2026-02-21 17:40:30 作者:

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 和模型解析过程——那才是你真正该调试的地方。

相关推荐

热文推荐