Entity Framework核心:one-to-one配置

Entity Framework Core: one-to-one configuration

我更新了标题以使其更相关。

我有两个 object,我希望先使用 EF Core 将它们映射到数据库。

为简洁起见,我将它们缩短了一些。

WeddingDetails
{
    VenueDetails ReceptionDetails { get; set; }
    VenueDeails  WeddingDetails { get; set; }
}

VenueDetails
{
   string StreetAddress { get; set; }
   string PostCode { get; set; }

   public int WeddingDetailsId { get; private set; }
   public WeddingDetails WeddingDetails { get; private set; }
}

然而,在尝试进行初始迁移时,我从 Entity Framework Core 收到以下错误:

Unable to determine the relationship represented by navigation 'WeddingDetails.ReceptionDetails' of type 'VenueDetails'. Either manually configure the relationship, or ignore this property using the '[NotMapped]' attribute or by using 'EntityTypeBuilder.Ignore' in 'OnModelCreating'.

问题是 receptiondetails 和 weddingdetails 是相同的 object,我相信当 Entity Framework Core 尝试将其转换为迁移时,这会导致冲突。

任何人都可以帮助我了解我必须使用 Fluent API/changes 添加到 OnModelCreating 方法的哪些配置选项我需要对 object 进行平滑此冲突,谢谢。

编辑

我实际上是通过创建一个 parent class 来解决这个问题的他们在table中使用鉴别器。

所以我更新如下

VenueDetails
{
   string StreetAddress { get; set; }
   string PostCode { get; set; }
}
WeddingVenueDetails : VenueDetails
{
}
ReceptionVenueDetails : VenueDetails
{
}

EF 然后能够解析它。我把答案给史蒂夫而不是自己回答的原因是,这不是我决定采用的方法,而是他建议的,实际上将两个 classes 分解成它们的方法拥有 objects 以允许未来的灵活性和解耦

就关系中 FK 的位置而言,这里的关系有点倒退。 One-to-One 关系通常由双方的 PK 关联,但是可以将 EF 配置为使用 one-to-many db-side 关系(FK on Right-side table) 或许多-to-one db-side 关系(FK on Left-side table)

例如,给定您的预期结构 /w Wedding 和 Venues,您希望单个 Wedding 指向 WeddingVenue 和 ReceptionVenue。下一个问题是 FK 应该位于何处。在 WeddingVenue 的情况下,您已将其设置为 one-to-many FK,并在 Venue table 中使用 WeddingID。但是,这让数据库如何计算 ReceptionVenue 的 FK 变得悬而未决。

您可以通过切换到多 to-one FK 来解决此问题,其中 WeddingVenueId 和 ReceptionVenueId 是婚礼 table/entity 的一部分。如果我们在实体中公开 FK 属性作为示例:

public class WeddingDetails
{
    [Key]
    public int WeddingDetailsId { get; set; }

    // ... wedding fields...

    public int WeddingVenueId { get; set; }
    public int ReceptionVenueId { get; set; }

    [ForeignKey("WeddingVenueId")]
    public virtual VenueDetails WeddingVenueDetails { get; set; } 
    [ForeignKey("ReceptionVenueId")]
    public virtual VenueDetails ReceptionVenueDetails { get; set; } 
}

现在,这在技术上建立了两个多 to-one 关系,其中模型配置如下所示:

modelBuilder.Entity<WeddingDetails>()
    .HasOne(x => x.WeddingVenueDetails)
    .WithMany();

但是,我们想要 VenueDetails 上的 WeddingDetails 实例。 ReceptionVenueDetails 是 VenueDetails 的另一个考虑因素是,该场所 不会 有 WeddingDetails 参考,因此将这种关系保留为 many-to-one 可能是有意义的。 =17=]

这里的问题是没有什么可以阻止来自以下位置的相同场地记录:

  • 同时用作婚礼场地和招待会场地。
  • 被用作婚礼and/or完全不同的婚礼的接待场所。

这意味着 如果 两场婚礼链接到同一个场地记录,一个婚礼场地的更新将反映在链接到同一记录的任何其他婚礼上。即使我们将 EF 配置为期望它们是一个 to-one 关系(我们可以使用 HasPrincipalKey 使用 EF Core 5/6),事实是数据库 FK 约束将始终允许两个婚礼参考相同的场地记录。这形成了一个虚假的一对 to-one 关系。

将此作为一个正确的方式执行的方法-to-one 要么将场地详细信息(用于婚礼和招待会)嵌入婚礼 table(作为 same-table EF Core 中的拥有类型)或者,将 WeddingVenueDetails 建立为一个 to-one 关系 table。 (使用标准的 one-to-one PK 关系或单独的 table 拥有的类型)

实体看起来像什么:

public class WeddingDetails
{
    [Key]
    public int WeddingDetailsId { get; set; }

    // ... wedding fields...
    public virtual WeddingVenueDetails WeddingVenueDetails { get; set; }
}

public class WeddingVenueDetails
{
    [Key]
    public int WeddingDetailsId { get; set; }

    string WeddingStreetAddress { get; set; }
    string WeddingPostCode { get; set; }

    string ReceptionStreetAddress { get; set; }
    string ReceptionPostCode { get; set; }

    public virtual WeddingDetails WeddingDetails { get; set; }
}

此处 WeddingVenueDetails 负责单个特定婚礼的婚礼和接待场地详细信息。我们可以在两者之间建立一个适当的one-to-one关系:

modelBuilder.Entity<WeddingDetails>()
    .HasOne(x => x.WeddingVenueDetails) // or OwnsOne()
    .WithOne(x => x.WeddingDetails);

在数据库 table 中,WeddingDetailsId 用作 table 和 FK 约束之间的唯一 PK。这强制实施了一种纯粹的 to-one 关系,在这种关系中,可以安全地独立编辑任何婚礼的场地详细信息,而不会影响任何其他婚礼的场地。

同样,如果您想将 WeddingVenue 和 ReceptionVenue 分开,您可以这样做,但是每个都需要自己单独的 table,并使用 WeddingDetailsID 作为 PK 并设置相同的 HasOne /WithOne。 (WeddingVenueDetails 和 ReceptionVenueDetails tables)它们不能是相同的 VenueDetails table/entity 以强制与 WeddingDetails 建立纯一to-one 关系。 (不存在 One-to-Two 或 One-to-Zero-or-Two 关系。)这可能看起来 non-ideal 因为这两个 table 会有效地共享相同的列,但是来自存储POV 无论是 2 条记录存储在 1 table 中,还是 1 条记录存储在两个 table 中,本质上是相同的。它还适应未来的灵活性,您可能拥有仅适用于婚礼或招待会的场地字段,可以将其添加到适当的 table 而无需求助于条件 Null-able 列。最坏的情况是,您最终不得不求助于 null-able 列,这些列暗示一个或另一个需要,而实际上没有在数据库中强制执行该列。如果在单个场地 table.

中,如果接待处之类的东西是可选的,以避免带有一堆空列的行,单独的 table 也会更好。