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

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


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


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

);

模型类定义为:


[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; }

}

为了告诉 efslaves有一个组合键,我覆盖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.


???


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


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


我是否真的必须向从表添加专用的 id 列才能使其与 ef-core 一起使用,还是有其他解决方案?


基于SBFrancies提示的解决方案


将一个字段添加到Slave名为的基类Discriminator:


[Column("Discriminator")]

[Required]

public abstract string Discriminator { get; set; }

实施变革SlaveA和SlaveB:


public override string Discriminator

{

    get => nameof(SlaveA); 

    set { }

}


不负相思意
浏览 154回答 1
1回答

素胚勾勒不出你

两个从站具有相同的 MasterID(“Master 01”)和相同的鉴别器(空),因此它们具有相同的主键,这导致了问题。更新一种可能的解决方案是为每种类型添加一个鉴别器:public class SlaveA : Slave{&nbsp; &nbsp; public string Discriminator => "S1";&nbsp; &nbsp; [Column("SlaveAValue")]&nbsp; &nbsp; [Required]&nbsp; &nbsp; public string SlaveAValue { get; set; }}public class SlaveB : Slave{&nbsp; &nbsp; public string Discriminator => "S2";&nbsp; &nbsp; [Column("SlaveBValue")]&nbsp; &nbsp; [Required]&nbsp; &nbsp; public string SlaveBValue { get; set; }}替代方案对以上内容表示歉意。我认为更好的选择是在 Slaves 表上有一个新的人工主键。CREATE TABLE Slaves (&nbsp; &nbsp; SlavesId INT NOT NULL IDENTITY PRIMARY KEY,&nbsp; &nbsp; MasterId VARCHAR2 NOT NULL,&nbsp; &nbsp; Discriminator VARCHAR2 NOT NULL,&nbsp; &nbsp; SlaveAValue VARCHAR2,&nbsp; &nbsp; SlaveBValue VARCHAR2,&nbsp; &nbsp; FOREIGN KEY (MasterId) REFERENCES Master(Id) ON DELETE CASCADE);[Table("Slaves")]public abstract class Slave{&nbsp; &nbsp; [Column("SlaveId")]&nbsp; &nbsp; [Key]&nbsp; &nbsp; public int SlaveId {get;set;}&nbsp; &nbsp; [Column("MasterId")]&nbsp; &nbsp; [Required]&nbsp; &nbsp; public string MasterId { get; set; }&nbsp; &nbsp; [ForeignKey("MasterId")]&nbsp; &nbsp; public Master Master { get; set; }}然后在您的数据库中添加一个唯一索引,以确保每个 master 类型不会超过一种:CREATE UNIQUE INDEX master_index ON Slaves(MasterId, Discriminator);
打开App,查看更多内容
随时随地看视频慕课网APP