为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

C#
不负相思意 2021-10-23 17:27:52
我正在尝试使用一对多关系和 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); // Exceptionawait 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 { }}
查看完整描述

1 回答

?
素胚勾勒不出你

TA贡献1827条经验 获得超9个赞

两个从站具有相同的 MasterID(“Master 01”)和相同的鉴别器(空),因此它们具有相同的主键,这导致了问题。


更新


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


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 表上有一个新的人工主键。


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

}

然后在您的数据库中添加一个唯一索引,以确保每个 master 类型不会超过一种:


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


查看完整回答
反对 回复 2021-10-23
  • 1 回答
  • 0 关注
  • 153 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信