注意,本文以 Entity Framework Core 9 为基准进行测试。
省流
当外键属性未提供 Setter 时,EF Core 仍然可以为其更新外键实体 Id,不会受到影响。
详细探讨
在使用 EF Core 操作数据库时,我根据实体的设计目的,将实体设计为如下:
public class Entity
{
public long Id { get; init; }
// 主角, 关联的子实体类和它的外键属性.
public required SubEntity SubEntity { get; init; } = null!;
public required long SubEntityId { get; init; }
}
public class SubEntity
{
public long Id { get; init; }
public required string Name { get; init; }
}
然后我将 DbContext 设计为:
public class AppDbContext : DbContext
{
public DbSet<Entity.Entity> Entities { get; internal init; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
// 示例代码所使用的数据库.
optionsBuilder.UseSqlite("Data Source=./app.db");
}
protected override void OnModelCreating(ModelBuilder builder)
{
// 设置 Entity 与 SubEntity 的关系.
builder.Entity<Entity.Entity>()
.HasOne(e => e.SubEntity)
.WithOne()
.HasForeignKey<Entity.Entity>(g => g.SubEntityId)
.OnDelete(DeleteBehavior.Restrict);
}
}
由于 SubEntity 会跟着 Entity 一起创建,因此我会先将 SubEntity 创建好,并设置到 Entity.SubEntity
属性中,但由于 Entity.SubEntityId
是 required 的,因此在创建实体实例时,我将其设为了 0
,就像这样:
var subEntity = new SubEntity
{
Name = "SubEntity 1"
};
var entity = new Entity.Entity
{
SubEntity = subEntity,
SubEntityId = 0
};
那么,当 Entity 被保存时,EF Core 是否能更新 Entity.SubEntityId
属性呢?因此我们调整一下测试代码(这里使用顶层代码以简化代码):
using EF_Core_Test_01.Data;
using EF_Core_Test_01.Entity;
var dbContext = new AppDbContext();
var subEntity = new SubEntity
{
Name = "SubEntity 1"
};
var entity = new Entity
{
SubEntity = subEntity,
SubEntityId = 0
};
Console.WriteLine($"Before Add Entity Id: {entity.Id}");
Console.WriteLine($"Before Add SubEntity Id Attribute: {entity.SubEntityId}");
dbContext.Entities.Add(entity);
Console.WriteLine($"Before Saves Entity Id: {entity.Id}");
Console.WriteLine($"Before Saves SubEntity Id Attribute: {entity.SubEntityId}");
dbContext.SaveChanges();
Console.WriteLine($"After Saves Entity Id: {entity.Id}");
Console.WriteLine($"After Saves SubEntity Id Attribute: {entity.SubEntityId}");
最后我们来看一下控制台输出:
Before Add Entity Id: 0
Before Add SubEntity Id Attribute: 0
Before Saves Entity Id: 0
Before Saves SubEntity Id Attribute: 0
After Saves Entity Id: 2
After Saves SubEntity Id Attribute: 2
可以从控制台输出看到,当执行 DbContext.SaveChanges()
时,Entity 和 SubEntity 都会得到数据库生成的 Id,并且 Entity.SubEntityId
已经被更新为 SubEntity 的 Id,因此即使外键导航属性未设置 Setter 也不会影响 EF Core 更新。