2个表之间的关系 - 一对多&一对一(可空)EF Code First

时间:2017-12-25 02:19:33

标签: .net vb.net entity-framework foreign-keys relationship

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

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

我有2个表TransmitterCalibration

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

现在Transmitter应该有一个OfficialCalibration,可以为空,例如在没有校准的情况下。

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

因此,如果没有"加入" -Table在EF Code First中,可以做到这一点?

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

  1. 我需要在校准中导航属性Tranmitters,我不想要
  2. 它不起作用,因为当我"注册"发送器ActualCalibrationId为Null,因为此发送器没有校准。
  3. 现在我试过了:

    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

    通过这种方式,我无法强制校准为OfficialCalibration只有一个Transmitter对吗?我可以用某种方式强行吗?我只能考虑使用包含Transmitter_DefaultCalbrationTransmitterId列的加入表CalibrationId并使TransmitterId成为主键?

    enter image description here

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

1 个答案:

答案 0 :(得分:1)

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

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

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

如果您不想要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);
    }

}