Code First 不是“先写代码再生成数据库”的简单流程,而是以 C# 类(实体)为唯一数据模型源头,由 EF Core 自动推导并管理数据库结构的开发模式。它要求你放弃手动建表思维,把注意力放在领域对象设计和迁移生命周期上。
定义实体类时必须注意的三个约束
EF Core 会根据约定自动映射属性,但一旦违反默认规则,就会导致迁移失败或运行时报错
InvalidOperationException。
public属性且有
get和
set访问器才会被识别为字段;
private set可接受,但
readonly字段或只读属性不会映射 主键命名必须是
Id或
{ClassName}Id(如 UserId),否则需用
[Key]显式标记 导航属性(如
public ICollection<order> Orders { get; set; }</order>)必须声明为 virtual(启用延迟加载时)或使用
Include()显式加载,否则查询时为空
DbContext 子类中如何正确配置关系
仅靠属性命名无法表达所有关系类型(如一对多、多对多、自引用)。必须重写
OnModelCreating方法,用 Fluent API 补充约定之外的逻辑。
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Order>()
.HasOne(o => o.User)
.WithMany(u => u.Orders)
.HasForeignKey(o => o.UserId);
<pre class='brush:php;toolbar:false;'>modelBuilder.Entity<User>()
.HasIndex(u => u.Email)
.IsUnique();
modelBuilder.Entity<PostTag>()
.HasKey(pt => new { pt.PostId, pt.TagId });}
常见疏漏:
HasOne().WithMany()忘记配对反向导航属性,或在多对多中间表中没用
HasKey显式指定复合主键,会导致迁移生成错误的外键约束。
执行迁移时最容易出错的三步操作
迁移不是“一键生成”,而是一系列可审查、可回滚的变更脚本。跳过其中任意一步,都可能让本地数据库与代码模型脱节。
修改实体后,必须先运行dotnet ef migrations add InitialCreate(或带描述的名称),生成
Migrations/xxx_InitialCreate.cs—— 这个文件不能手动改,它是 EF Core 推导出的“差量” 检查生成的
Up(MigrationBuilder migrationBuilder)方法是否符合预期,比如字段类型是否正确(
string默认映射为
nvarchar(max),常需用
HasMaxLength(50)限制) 执行
dotnet ef database update才真正应用变更;若想回退,用
dotnet ef database update PreviousMigrationName,而不是删掉迁移文件
生产环境禁用 Database.EnsureCreated()
这个方法会直接删库重建,在开发阶段看似方便,但一旦误部署到测试或生产环境,后果不可逆。
替代方案只有且必须是迁移:
首次部署:运行dotnet ef database update应用全部待迁移 后续更新:每次发布前生成新迁移,上线时执行
update到最新版本 若需初始化空库,可用
dotnet ef migrations script --idempotent生成兼容性脚本,供 DBA 审核执行
真正难的不是写第一个
DbContext,而是让团队所有人理解:迁移文件是代码的一部分,要进 Git、要 Code Review、要和实体变更保持原子性 —— 否则迟早遇到
Microsoft.Data.SqlClient.SqlException: Invalid object name 'Users'这类运行时错误。
