EF Core使用SQLite时Owned实体隐式主键触发非空约束报错如何解决
问题原因
EF Core 针对集合类型的Owned实体(Owned Many),默认会为其生成联合隐式主键:[所有者外键列, 隐式Id列],比如本例中的[PostId, Id],其中隐式的Id列是整数类型,用于区分同一个Post下的不同Comment。
- PostgreSQL等数据库的EF Core提供程序,默认会自动为这个隐式
Id列配置添加时自动生成值的策略,插入数据时无需手动赋值,数据库会自动生成合法值,因此运行正常。 - SQLite的EF Core提供程序,没有为Owned实体的隐式主键列默认启用自动值生成,插入时EF Core不会为
Id字段生成值,触发SQLite的NOT NULL约束报错。
如果你用HashSet<T>作为Owned集合的存储实现,因为HashSet是无序无索引的集合,EF Core无法通过顺序索引为隐式Id生成临时值,也会加重这个问题。
修复方案
方案1:显式配置隐式主键的自动生成策略(最稳妥,推荐)
在Owned实体的配置代码中,手动为隐式Id字段启用值自动生成,修改配置如下:
builder.OwnsMany(x => x.Comments, x => { // 新增这一行,显式配置隐式Id列插入时自动生成值 x.Property<int>("Id").ValueGeneratedOnAdd(); x.Property(y => y.Text).IsRequired(); });
该方案不需要修改实体定义,适配所有数据库提供程序。
方案2:将集合实现替换为有序集合
将Post实体中Comments的默认实现从无序的HashSet<Comment>改为有序的List<Comment>:
public class Post { public Post(string content) { Content = content; } public long Id { get; private set; } public string Content { get; private set; } // 将HashSet改为List即可 public ICollection<Comment> Comments { get; private set; } = new List<Comment>(); }
EF Core可以根据有序集合的索引,自动为Owned实体的隐式Id生成临时值,满足SQLite的插入要求。
方案3:显式为Comment定义主键
如果后续有单独操作Comment的需求,可以直接在Comment实体中显式定义主键属性:
public class Comment { public Comment(string text) { Text = text; } // 新增显式主键 public int Id { get; private set; } public string Text { get; private set; } }
EF Core会自动识别该字段为主键并配置自动生成策略,无需额外修改配置。
内容的提问来源于stack exchange,提问作者lonix
相关产品推荐
相关产品推荐

