调用DbContext.AddAsync后Owned Property被设为NULL的问题
EF Core中Owned Entity添加到上下文后被置为NULL的问题
实体定义
public class Audio { public Guid Id { get; } public VoiceInfo VoiceInfo { get; } } public class VoiceInfo { public VoiceProvider Provider { get; } public Language Language { get; } public Gender Gender { get; } public string Name { get; } }
映射配置
builder.OwnsOne(x => x.VoiceInfo, v => { v.Property(x => x.Gender).HasColumnName(nameof(VoiceInfo.Gender)); v.Property(x => x.Language).HasColumnName(nameof(VoiceInfo.Language)); v.Property(x => x.Name).HasColumnName(nameof(VoiceInfo.Name)); v.Property(x => x.Provider).HasColumnName(nameof(VoiceInfo.Provider)); });
问题重现
创建包含VoiceInfo的Audio实例后,执行以下代码:
await DbContext.AddAsync(audio);
随后调用:
DbContext.SaveChanges();
抛出异常:
...无法将值 NULL 插入列 'Language'...
更奇怪的是,调用AddAsync(audio)后,Audio实例的VoiceInfo属性被设为NULL,这直接导致了上述异常,但为什么添加到上下文后Owned Property会被置为NULL?
状态检查
调用AddAsync()前后添加了状态检查代码:
var entry = Entry(audio); var entityState = entry.State; var ownedPropertyState = entry.Reference(x => x.VoiceInfo).TargetEntry.State;
- 调用前:
entityState和ownedPropertyState均为Detached,符合预期。 - 调用后:
entityState变为Added,但获取ownedPropertyState时抛出异常:对象引用未设置到对象的实例。
原因分析
问题根源在于实体属性的访问器设计:Audio.VoiceInfo和VoiceInfo的所有属性都只有get访问器,没有set访问器。EF Core在跟踪实体时,需要能够设置这些属性的值(比如附加上下文后的代理生成、状态同步),只读属性会打破EF Core的实体跟踪机制,最终导致VoiceInfo被置为NULL。
Owned Entity的机制要求其属性必须允许EF Core进行赋值操作,只读属性会让框架无法正确处理关联状态。
解决办法
- 给
Audio.VoiceInfo添加私有或公共set访问器,同时保留封装性(推荐私有setter+构造函数初始化):
public class Audio { public Guid Id { get; } public VoiceInfo VoiceInfo { get; private set; } public Audio(Guid id, VoiceInfo voiceInfo) { Id = id; VoiceInfo = voiceInfo; } }
- 给
VoiceInfo的所有属性添加私有或公共set访问器,同样用构造函数初始化属性:
public class VoiceInfo { public VoiceProvider Provider { get; private set; } public Language Language { get; private set; } public Gender Gender { get; private set; } public string Name { get; private set; } public VoiceInfo(VoiceProvider provider, Language language, Gender gender, string name) { Provider = provider; Language = language; Gender = gender; Name = name; } }
修改后,EF Core就能正确跟踪Owned Entity的状态,不会将VoiceInfo置为NULL,SaveChanges()也能正常执行,不会出现列值为NULL的异常。
内容的提问来源于stack exchange,提问作者miechooy
相关产品推荐
相关产品推荐

