EF Core 一对一关系配置的核心在于明确“谁是主体(Principal)、谁是依赖(Dependent)”,并正确指定外键归属和导航方向。不加外键或搞反主从关系,会导致迁移失败或数据不一致。
基本配置:用 HasOne + WithOne + HasForeignKey
这是最常用、最清晰的方式。推荐从主体实体出发配置:
主体实体(如User)拥有导航属性指向依赖实体(
UserProfile) 依赖实体(如
UserProfile)包含外键字段(如
UserId),且该字段需唯一(EF Core 自动加唯一索引) 在
OnModelCreating中写:
modelBuilder.Entity<User>()
.HasOne(u => u.Profile) // User 有一个 Profile
.WithOne(p => p.User) // UserProfile 有一个 User
.HasForeignKey<UserProfile>(p => p.UserId); // 外键在 UserProfile 表里
等价写法(从依赖端配置)也合法,但建议统一从主体端写,逻辑更直观。
两种主键模式要分清
EF Core 支持两种常见一对一结构,选错会影响数据插入和查询行为:
共享主键(推荐):依赖实体的主键同时也是外键,值等于主体主键。例如UserProfile.Id == User.Id。
配置只需把
HasForeignKey指向
Id字段:
.HasForeignKey<userprofile>(p => p.Id)</userprofile>独立外键:依赖实体有自己主键(如
Id),另设一个非主键外键(如
UserId)。此时必须确保该外键列加了唯一约束(Fluent API 会自动处理)
关键细节不能漏
生产环境建议显式补全这些设置,避免默认行为引发意外:
.IsRequired():表示该关系是否强制存在(比如每个用户必须有资料)
.OnDelete(DeleteBehavior.Cascade):删除用户时是否级联删资料;若不希望级联,可用
Restrict或
ClientSetNull导航属性必须为
public virtual(启用延迟加载时)或至少可读写,否则 EF 可能无法正确映射
验证是否生效
配置完后执行迁移命令:
dotnet ef migrations add AddUserAndProfileRelationship
检查生成的迁移文件中,
UserProfile表是否含
UserId列(或与主键同名的列),且带
UNIQUE约束和外键引用 —— 这说明配置成功。
基本上就这些。不复杂但容易忽略外键归属和主从角色,配错就会查不到关联数据或报错。
