EF Core迁移自动创建TenantId1影子属性的问题及解决
EF Core迁移生成多余TenantId1列问题解决
问题背景
存在抽象类Device,由Machine和Line继承。迁移前Device包含string类型的TenantId属性,现在需引入Tenant类,将Device.TenantId改为int类型作为Tenant表的外键,实现每个Device对应一个Tenant。
实体类代码
public abstract class Device { public int Id { get; set; } public int TenantId { get; set; } public Tenant Tenant { get; set; } // 导航属性 }
public class Tenant { public int Id { get; set; } public string Name { get; set; } public List<Device> Devices { get; set; } = []; // 导航属性 public List<Line> Lines { get; set; } = []; // 导航属性 public List<Machine> Machines { get; set; } = []; // 导航属性 }
DB上下文配置代码
modelBuilder.Entity<Device>(builder => { builder.ToTable("Devices").HasKey(d => new { d.Id }); builder.HasDiscriminator(d => d.DeviceType) .HasValue<Machine>(DeviceType.Machine) .HasValue<Line>(DeviceType.Line); builder.HasOne(device => device.Tenant) .WithMany(tenant => tenant.Devices) .HasForeignKey(device => device.TenantId); }); modelBuilder.Entity<Machine>(builder => { builder.HasBaseType<Device>(); builder.HasOne(m => m.Line) .WithMany(dl => dl.Machines) .HasForeignKey(m => m.LineId); builder.HasOne<Tenant>() .WithMany(tenant => tenant.Machines) .HasForeignKey(device => device.TenantId); }); modelBuilder.Entity<Line>(builder => { builder.HasBaseType<Device>(); builder.HasOne<Tenant>() .WithMany(tenant => tenant.Lines) .HasForeignKey(device => device.TenantId); });
遇到的问题
创建迁移时,EF Core输出提示:
The foreign key property 'Device.TenantId1' was created in shadow state because a conflicting property with the simple name 'TenantId' exists in the entity type, but is either not mapped, is already used for another relationship, or is incompatible with the associated primary key type.
迁移操作中,除了将Devices表的TenantId列类型从text改为int(符合预期),还自动新增了TenantId1列:
migrationBuilder.AlterColumn<int>( name: "TenantId", table: "Devices", type: "integer", nullable: false, defaultValue: 0, oldClrType: typeof(string), oldType: "text", oldNullable: true); migrationBuilder.AddColumn<int>( name: "TenantId1", table: "Devices", type: "integer", nullable: true);
原因分析
基类Device已经配置了与Tenant的关联:通过TenantId外键关联到Tenant.Devices。但在派生类Machine和Line的配置中,又重复定义了与Tenant的关联,指定用同一个TenantId外键关联到Tenant.Machines和Tenant.Lines。
EF Core会将这些视为独立的关系,而TenantId已经被基类的关系占用,无法再复用,因此自动生成TenantId1影子属性来对应派生类的额外关系,最终导致迁移中新增列。
解决方案
移除派生类Machine和Line中重复的Tenant关联配置,因为继承自Device的关系会自动生效,无需重复定义。
修改后的DB上下文配置:
modelBuilder.Entity<Device>(builder => { builder.ToTable("Devices").HasKey(d => new { d.Id }); builder.HasDiscriminator(d => d.DeviceType) .HasValue<Machine>(DeviceType.Machine) .HasValue<Line>(DeviceType.Line); builder.HasOne(device => device.Tenant) .WithMany(tenant => tenant.Devices) .HasForeignKey(device => device.TenantId); }); modelBuilder.Entity<Machine>(builder => { builder.HasBaseType<Device>(); builder.HasOne(m => m.Line) .WithMany(dl => dl.Machines) .HasForeignKey(m => m.LineId); // 移除重复的Tenant关联配置 }); modelBuilder.Entity<Line>(builder => { builder.HasBaseType<Device>(); // 移除重复的Tenant关联配置 });
修改完成后,重新生成迁移,此时只会修改TenantId列的类型,不会再生成TenantId1列。
内容的提问来源于stack exchange,提问作者Andreas F
相关产品推荐
相关产品推荐

