【问题标题】:2 relations between 2 tables - One-to-many & one-to-one (nullable) EF Code First2 个表之间的 2 个关系 - 一对多和一对一(可为空)EF 代码优先
【发布时间】:2017-12-25 02:19:32
【问题描述】:

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

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

我有 2 个表 TransmitterCalibration

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

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

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

那么在 EF Code First 中没有“联接”表是否可以做到这一点?

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

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

现在我尝试了:

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 对吧?我可以通过某种方式强制吗?我只能考虑使用带有 TransmitterIdCalibrationId 列的 Join-Table Transmitter_DefaultCalbration 并将 TransmitterId 设为主键?

我仍在学习将 EF 用于复杂场景,因此任何信息或指导都会很好。

【问题讨论】:

  • 在 1:0..1 关联中,1 侧的实体(此处:发送器)是 主体,另一侧是 从属 i> 实体。主体实体生成(或接收)其主键,然后将其复制到从属实体的主键。因此 Id => Id 关系。如果您希望 OfficialCalibrationId 成为一个 OfficialCalibration 的 FK,您只能将其建模为第二个 1(校准):N(发射器)关联,并在代码中将其强制为 1:1。
  • @GertArnold 我最终按照你说的做了,并为 ActualCalibrationID 添加了一个过滤的(非空值)唯一索引。我认为这应该可行。

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


【解决方案1】:

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

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

其他答案:
- 通常,您不需要导航属性来定义关系(您只需要 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);
    }

}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-03-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-19
    • 1970-01-01
    相关资源
    最近更新 更多