EF Core SQLite TPH interitance组合键->重复键?

EF Core SQLite TPH interitance combined key -> duplicate key?

我正在尝试使用一对多关系和 TPH 映射设置一个简单的 SQLite 数据库。

Table 已使用以下命令应用创建:

CREATE TABLE Masters (Id VARCHAR2 PRIMARY KEY);

CREATE TABLE Slaves (
    MasterId VARCHAR2 NOT NULL,
    Discriminator VARCHAR2 NOT NULL,
    SlaveAValue VARCHAR2,
    SlaveBValue VARCHAR2,
    PRIMARY KEY (MasterId, Discriminator),
    FOREIGN KEY (MasterId) REFERENCES Master(Id) ON DELETE CASCADE
);

模型 classes 定义为:

[Table("Masters")]
public class Master
{
    [Column("Id")]
    [Key, Required]
    public string Id { get; set; }

    public List<Slave> Slaves { get; set; } = new List<Slave>();
}

[Table("Slaves")]
public abstract class Slave
{
    [Column("MasterId")]
    [Required]
    public string MasterId { get; set; }

    [ForeignKey("MasterId")]
    public Master Master { get; set; }
}

public class SlaveA : Slave
{
    [Column("SlaveAValue")]
    [Required]
    public string SlaveAValue { get; set; }
}

public class SlaveB : Slave
{
    [Column("SlaveBValue")]
    [Required]
    public string SlaveBValue { get; set; }
}

为了告诉 ef slaves 有一个组合键,我覆盖了 OnModelCreating 的内容:

modelbuilder.Entity<Slave>().HasKey("MasterId", "Discriminator");
base.OnModelCreating(modelbuilder);

但是,如果我尝试向上下文添加一个值,则会出现异常:

var master = new Master { Id = "Master 01" };
var slaveA = new SlaveA { Master = master, SlaveAValue = "A 01" };
var slaveB = new SlaveB { Master = master, SlaveBValue = "B 01" };

master.Slaves.Add(slaveA);
master.Slaves.Add(slaveB);

await context.Masters.AddAsync(master); // Exception
await context.SaveChangesAsync();

异常信息为:The instance of entity type 'SlaveB' cannot be tracked because another instance with the same key value for {'MasterId', 'Discriminator'} is already being tracked.

???

数据库中的所有 table 都是空的(新创建的)。

我的猜测是 discriminator 值在将主值添加到上下文时尚未确定。添加一个包含 discriminiator 值的字段不会解决问题(我也猜到了,但试了一下...)。

我真的必须向从站添加一个专用的 id 列吗 table 以使其与 ef-core 一起工作,或者是否有任何其他解决方案?

基于 SBFrancies 提示的解决方案

向基 class Slave 添加一个名为 Discriminator:

的字段
[Column("Discriminator")]
[Required]
public abstract string Discriminator { get; set; }

更改SlaveASlaveB的实现:

public override string Discriminator
{
    get => nameof(SlaveA); 
    set { }
}

这两个从属具有相同的 MasterID ("Master 01") 和相同的鉴别器 (null),因此它们具有相同的主键,这就是导致问题的原因。

更新

一个可能的解决方案是为每种类型添加一个鉴别器:

public class SlaveA : Slave
{
    public string Discriminator => "S1";

    [Column("SlaveAValue")]
    [Required]
    public string SlaveAValue { get; set; }
}

public class SlaveB : Slave
{
    public string Discriminator => "S2";

    [Column("SlaveBValue")]
    [Required]
    public string SlaveBValue { get; set; }
}

备选方案

对上述内容表示歉意。我认为更好的选择是在 Slaves table.

上有一个新的人工主键
CREATE TABLE Slaves (
    SlavesId INT NOT NULL IDENTITY PRIMARY KEY,
    MasterId VARCHAR2 NOT NULL,
    Discriminator VARCHAR2 NOT NULL,
    SlaveAValue VARCHAR2,
    SlaveBValue VARCHAR2,
    FOREIGN KEY (MasterId) REFERENCES Master(Id) ON DELETE CASCADE
);

[Table("Slaves")]
public abstract class Slave
{

    [Column("SlaveId")]
    [Key]
    public int SlaveId {get;set;}

    [Column("MasterId")]
    [Required]
    public string MasterId { get; set; }

    [ForeignKey("MasterId")]
    public Master Master { get; set; }
}

然后在您的数据库中添加一个唯一索引,以确保您没有超过一种类型的每个主控:

CREATE UNIQUE INDEX master_index ON Slaves(MasterId, Discriminator);