首页 > 解决方案 > 如何处理同一实体类型的多个一对零或一关系?

问题描述

据我了解,EF6 通过在相关实体上共享相同的 ID 实现一对零或一关系投影到数据库中

教程说:

当一个表的主键在关系数据库(如 SQL Server)中的另一个表中变为 PK 和 FK 时,就会发生一对零或一关系。因此,我们需要以这样的方式配置上述实体,即EF在DB中创建Students和StudentAddresses表,并将Student表中的StudentId列作为PrimaryKey(PK),将StudentAddresses表中的StudentAddressId列作为PK和ForeignKey(FK ) 两个都。

所以如果 aWebsite有一个 optional WebsitePage,我可能会有这个:

public class Website
{
    public int Id { get; set; }
    public virtual WebsitePage Page { get; set; }
}


public class WebsitePage
{
    [Key, ForeignKey( nameof( Website ) )]
    public int Id { get; set; } 
    public virtual Website Website { get; set; }
}

但是如果我想要多个可选页面,像这样呢?

public class Website
{
    public int Id { get; set; }
    public virtual WebsitePage AboutPage { get; set; }
    public virtual WebsitePage ServicesPage { get; set; }
    public virtual WebsitePage CaseStudyPage { get; set; }
}


public class WebsitePage
{
    [Key, ForeignKey( nameof( Website ) )]
    public int Id { get; set; } 
    public virtual Website Website { get; set; }
}

可能是我今天的谷歌搜索不合格,但我无法在网上或在 SO 上找到任何此类示例。

我错过了什么,还是我的理解有缺陷?

标签: asp.net-mvcentity-frameworkprimary-key

解决方案


最初我误解了你想要实现的关系的标题。当我们在另一个模型中有多个引用时,无法完成一对零或一关系。你要求的是一对多的关系;一方面,我们有 1 个WebsitePage对象,另一方面,我们有n相关的Website对象,可以有 1-3WebsitePage秒(请参阅评论)。为此,您可以使用Nullable Foreign Keys。在导航属性旁边提供可为空的 ID 属性:

public class Website
{
  [Key]
  public int Id { get; set; }

  public int? AboutPageId { get; set; }
  public virtual WebsitePage AboutPage { get; set; }

  public int? ServicesPageId { get; set; }
  public virtual WebsitePage ServicesPage { get; set; }

  public int? CaseStudyPageId { get; set; }
  public virtual WebsitePage CaseStudyPage { get; set; }
}


public class WebsitePage
{
  [Key]
  public int Id { get; set; }
}

WebsiteIdWebsitePage模型中是没有必要的。请参阅EF6 内置约定

您也可以使用 Fluent API,就像他们在您链接的教程中所做的那样。

编辑:如果您希望每个页面仅属于一个网站,您可能需要分离模型并使用中间模型:

public class Website
{
  [Key]
  public int Id { get; set; }

  public virtual IList<WebsitePage> WebsitePages { get; set; }
}

public class Page
{
  [Key]
  public int Id { get; set; }

  //public PageType Type { get; set; }

  public virtual IList<WebsitePage> WebsitePages { get; set; }
}

public class WebsitePage
{
  [Key, ForeignKey(nameof(Page))]
  public int PageId { get; set; }
  public virtual Page Page { get; set; }

  public int WebsiteId { get; set; }
  public virtual Website Website { get; set; }
}

PageId不能重复,每条记录都需要一个WebsiteId; 每个页面将只属于一个网站(如果有)。它使用 .NET Core 3.1/EF Core 2.2 进行了测试。

同样,您可能只能使用两个模型 (WebsitePage) 和 Fluent API 来指定它们之间的多对多关系必须如何防止重复。


推荐阅读