EF Core JSON列自引用拥有类型迁移报错求助
解决EF Core将实体保存到SQL Server JSON列时的迁移报错问题
问题描述
尝试把嵌套实体模型存入SQL Server的JSON列,运行Add-Migration version命令时触发以下错误:
无法确定“VersionItemsEntity.Children#VersionItemsEntity.Data”与“VersionItemsDataEntity”之间关系的所有者,因为这两种类型都已标记为拥有类型。请手动配置所有权,或使用[NotMapped]特性或在OnModelCreating中使用“EntityTypeBuilder.Ignore”忽略相应的导航属性。
相关实体模型与原配置代码如下:
实体模型代码
public class VersionEntity { public VersionEntity() { } public VersionItemEntity Items { get; set; } public long ProjectId { get; set; } public int TenantId { get; set; } } public class VersionItemEntity { public List<VersionItemsEntity> VersionItems { get; set; } } public class VersionItemsEntity { public VersionItemsEntity() { } public string Key { get; set; } public string Label { get; set; } public VersionItemsDataEntity Data { get; set; } public string Icon { get; set; } public List<VersionItemsEntity> Children { get; set; } = new(); } public class VersionItemsDataEntity { public string Title { get; set; } public int? Order { get; set; } public DateTime? ReleaseDate { get; set; } }
原OnModelCreating配置
private void VersionModelCreating(ModelBuilder modelBuilder) { modelBuilder.Ignore<VersionItemsDataEntity>(); modelBuilder.Entity<VersionEntity>().OwnsOne( version => version.Items, ownedNavigationBuilder => { ownedNavigationBuilder.OwnsMany( metadata => metadata.VersionItems, ownedOwnedNavigationBuilder => { ownedOwnedNavigationBuilder.OwnsMany(vi => vi.Children); ownedOwnedNavigationBuilder.OwnsOne(vi => vi.Data); ownedNavigationBuilder.ToJson(); } ); }); modelBuilder.Entity<VersionEntity>().Property(o => o.Id).UseIdentityColumn(Back_SoftConsts.InitialValue); }
问题根源
- 错误调用
modelBuilder.Ignore<VersionItemsDataEntity>(),但实体中需要用该类型作为导航属性,忽略操作导致EF无法识别其所有权关系。 ToJson()方法位置错误,应在最上层的拥有类型(Items)配置中调用,而非嵌套在OwnsMany的层级里。- 嵌套的
Children集合中的Data属性未明确配置所有权,EF无法解析该关系。
解决方案
修改VersionModelCreating方法,调整配置层级,明确所有嵌套拥有类型的关系,移除错误的Ignore调用:
private void VersionModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<VersionEntity>(entity => { // 配置Id自增规则 entity.Property(o => o.Id).UseIdentityColumn(Back_SoftConsts.InitialValue); // 配置Items为拥有类型,并转为JSON列存储 entity.OwnsOne(version => version.Items, ownedNavigationBuilder => { ownedNavigationBuilder.ToJson(); // 将整个Items对象序列化为JSON // 配置VersionItems集合 ownedNavigationBuilder.OwnsMany(metadata => metadata.VersionItems, versionItemsBuilder => { // 明确当前VersionItems的Data属性所有权 versionItemsBuilder.OwnsOne(vi => vi.Data); // 递归配置Children集合 versionItemsBuilder.OwnsMany(vi => vi.Children, childrenBuilder => { // 明确Children中Data属性的所有权 childrenBuilder.OwnsOne(c => c.Data); }); }); }); }); }
说明
- 移除
modelBuilder.Ignore<VersionItemsDataEntity>(),因为VersionItemsEntity依赖该类型作为拥有属性,不能忽略。 - 将
ToJson()放在Items的拥有类型配置中,确保整个Items对象(含所有嵌套集合与属性)都被序列化为JSON存入SQL Server。 - 对
Children内部的Data属性显式调用OwnsOne,明确所有权关系,解决EF的识别问题。
修改完成后重新运行Add-Migration version即可正常生成迁移文件。
内容的提问来源于stack exchange,提问作者Iman Bahrampour
相关产品推荐
相关产品推荐

