Asp.Net Core 如何配置复杂类型属性实现同表列映射解决迁移报错
报错根因
你给NameSet类添加的[Keyless]特性,会让EF Core将其识别为独立的无键实体,而非要拆分到Customer表中的嵌套值对象。此时EF Core会自动把Customer.Name属性判定为两个实体间的导航属性,因为找不到对应的关系配置,就会抛出你遇到的报错。
要让生成的表结构完全符合预期(把NameSet的三个属性直接映射为Customer表的同表列,不生成独立的NameSet表),需要将NameSet配置为Customer的拥有类型(Owned Type),具体有两种配置路径:
方式1:通过数据注解配置
- 移除
NameSet类上的[Keyless]特性,这个特性会强制将类识别为独立实体,是触发报错的核心原因 - 给
Customer类中的Name属性添加[Owned]标记,告知EF该类型是依附于Customer存在的嵌套对象
修改后的模型代码:
public class NameSet { public string FirstName { get; set; } public string MiddleName { get; set; } public string LastName { get; set; } } public class Customer { public int Id { get; set; } [Owned] public NameSet Name { get; set; } public string Mobile { get; set; } public string Email { get; set; } public bool IsActive { get; set; } }
注意:这种默认配置下,EF生成的列名会自动加上
Name_前缀(比如Name_FirstName),和你需要的无前缀列结构不匹配,还需要补充列名映射配置。
方式2:通过DbContext的Fluent API配置(推荐,灵活度更高)
不需要修改模型上的注解,直接在ApplicationDbContext的OnModelCreating方法中完成配置,同时可以手动指定匹配需求的列名:
protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<Customer>(customer => { // 配置Customer的Name属性为拥有类型,嵌套属性直接映射到当前Customer表 customer.OwnsOne(c => c.Name, ownedNav => { // 手动指定每个属性对应的数据库列名,去掉默认的Name_前缀 ownedNav.Property(n => n.FirstName).HasColumnName("FirstName"); ownedNav.Property(n => n.MiddleName).HasColumnName("MiddleName"); ownedNav.Property(n => n.LastName).HasColumnName("LastName"); }); }); }
配置注意事项
- 不要在
ApplicationDbContext中单独为NameSet添加DbSet声明,否则EF会再次将其识别为独立实体,导致配置失效 - 配置完成后重新执行
add-migration,生成的迁移脚本就会完全匹配预期的表结构,不会再出现导航属性识别的报错
内容的提问来源于stack exchange,提问作者anand
相关产品推荐
相关产品推荐

