EF Core 在迁移中创建“Id1”影子属性

问题描述 投票:0回答:1

我有一个名为

Device
的抽象类。它由两个类
Machine
Line
扩展。

迁移之前

Device
有一个名为
TenantId
的字符串属性。

迁移
我正在介绍一个名为

Tenant
的课程。每个设备都有一个租户。我将
Device.TenantId
的类型从 string 更改为 int。现在它是
Tenant
表的外键。

这是代码(类和数据库上下文配置):

public abstract class Device
    {
        public int Id { get; set; }

        public int TenantId { get; set; }

        public Tenant Tenant { get; set; } // Navigation property
public class Tenant
{
    public int Id { get; set; }

    public string Name { get; set; }

    public List<Device> Devices { get; set; } = []; // Navigation property

    public List<Line> Lines { get; set; } = []; // Navigation property

    public List<Machine> Machines { get; set; } = []; // Navigation property
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);
            });

问题
当我创建迁移时,它输出:

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. See https://aka.ms/efcore-relationships for information on mapping relationships in EF Core.

然后,它将

TenantId
列的类型从 text 更改为 int (正确),但还添加了一个新列:

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);

我的期望是不需要

TenantId1
。我不知道为什么 EF 添加它,也不知道如何摆脱它。

我对这个问题迷失了,我已经研究这个问题几个小时了,但我找不到解决方案。

c# entity-framework-core entity-framework-migrations
1个回答
0
投票

当机器扩展设备时,删除:

public List<Machine> Machines { get; set; } = []; // Navigation property

连同配置:

builder.HasOne<Tenant>()
    .WithMany(tenant => tenant.Machines)
    .HasForeignKey(device => device.TenantId);

这使关系加倍,因此 EF 将需要机器/设备表上的第二个 FK(无论是 TPT/C 还是 TPH)。如果为了方便起见,您希望租户在运行时过滤“机器”:

[NotMapped]
public IEnumerable<Machine> Machines => Devices.OfType<Machine>();

但是您不能在查询表达式中使用它。例如,这是行不通的:

var tenant = _context.Tenants
    .Where(x => x.Machines.Any(m => /* some criteria */)
    .FirstOrDefault();

您必须通过设备检查才能找到机器:

var tenant = _context.Tenants
    .Where(x => x.Devices.OfType<Machine>().Any(m => /* some criteria */))
    .FirstOrDefault();

注意:还要从集合导航属性中删除设置器。 EF 集合永远不应该重新初始化,公共 setter 很危险,因为它们最终可能会破坏更改跟踪,导致保存时出错。

public List<Device> Devices { get; } = []; 

任何尝试设置集合的代码都是一个潜在的问题。

© www.soinside.com 2019 - 2024. All rights reserved.