2个表之间的关系 - 一对多和一对一(可空)EF代码优先

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2个表之间的关系 - 一对多和一对一(可空)EF代码优先相关的知识,希望对你有一定的参考价值。

我知道有很多关于这个问题的问题,但经过几天的思考后,我仍然无法弄清楚如何让它发挥作用。

我正在编写一个自动校准设备的应用程序。

我有2张桌子TransmitterCalibration

Transmitter可以有零个,一个或多个CalibrationCalibration必须属于发射器。

现在Transmitter应该有一个OfficialCalibration,可以为null,例如在没有校准完成的时候。

所以我想在没有joiner表的情况下实现这个,只需在Transmitter中有一个OfficialCalibrationId。 (两种方式我都需要更新2个表,但所以我的表总数更少)。也很好有这个关系作为navigationProperty所以我可以调用Transmitter.OfficialCalibration并获得正确的Calibration

因此,如果没有EF Code First中的“加入”表,可以这样做吗?

我尝试使用一对多关系和一个附加约束来定义一对一的方法,但这样我有2个问题

  1. 我需要在校准中导航属性Tranmitters,我不想要
  2. 它不起作用,因为当我“注册”发射器时,ActualCalibrationId为空,因为此发射器没有校准。

现在我试过了:

modelBuilder.Entity(of Transmitter)
    .HasMany(Function(c)c.Calibrations)
    .WithRequired(Function(t)t.Transmitter)
    .HasForeignKey(Function(t)t.TransmitterId)

但是仍然存在下图中显示的一对一关系的问题。

关系是Transmitter.Id - > Calibration.Id但应该是Transmitter.OfficialCalibrationId - > Calibration.Id

这样我就不能强制校准只是一个OfficialCalibrationTransmitter吧?我可以用某种方式强行吗?我只能想到使用连接表Transmitter_DefaultCalbration与列TransmitterIdCalibrationId并使TransmitterId成为主键?

enter image description here

我仍在学习使用EF进行复杂的场景,所以任何信息或指导都会很好。

答案

发送器 - 校准关系是1-n关系,因此您不需要连接表。

如您所知,您可以通过两种方式指定OfficialCalibration,在Transmitter上插入一个属性(Transmitter.OfficialCalibration)或在Calibration(Calibration.Default)中插入一个标志。两个关系都需要使用代码强制执行,因为: - 如果插入属性,则无法确定OfficialCalibration是与Transmitter相关的校准之一; - 如果插入标记,则无法确定只有一个正式校准。在写作时思考,可能这可以使用唯一索引来强制执行。

其他一些答案: - 通常,您不需要导航属性来定义关系(您只需要两个导航属性中的一个);

如果你不想要Calibrations属性,那么这就是C#中的模型

class Context : DbContext
{
    public DbSet<Transmitter> Transmitters { get; set; }
    public DbSet<Calibration> Calibrations { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Calibration>()
            .HasRequired(_ => _.Transmitter);
    }

}

class Calibration
{
    public int Id { get; set; }
    [MaxLength(50)]
    public string Description { get; set; }

    public virtual Transmitter Transmitter { get; set; }
}

class Transmitter
{
    public int Id { get; set; }
    [MaxLength(50)]
    public string Description { get; set; }
    public virtual Calibration OfficialCalibration { get; set; }
}

如果您首选默认属性,我将实现此模型(在这种情况下,我更喜欢具有Calibrations导航属性)

class Context : DbContext
{
    public DbSet<Transmitter> Transmitters { get; set; }
    public DbSet<Calibration> Calibrations { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Transmitter>()
            .HasMany(_ => _.Calibrations)
            .WithRequired(_ => _.Transmitter);
    }
}

class Calibration
{
    public int Id { get; set; }
    [MaxLength(50)]
    public string Description { get; set; }

    public bool? Default { get; set; }

    public virtual Transmitter Transmitter { get; set; }
}

class Transmitter
{
    public int Id { get; set; }
    [MaxLength(50)]
    public string Description { get; set; }

    public virtual ICollection<Calibration> Calibrations { get; set; }


    public Calibration GetOfficialCalibration()
    {
        // This could trigger lazy load
        return Calibrations.FirstOrDefault(_ => _.Default == true);
    }

}

以上是关于2个表之间的关系 - 一对多和一对一(可空)EF代码优先的主要内容,如果未能解决你的问题,请参考以下文章

两个棱镜模型之间的一对多和可能对多关系

同一实体之间的一对多和多对多关系

Hibernate映射关系:一对一对多和多对多

MyBatis之基于XML的表之间映射

EF-一对一关系

如何判断一对一对多和多对多的关系