【问题标题】:Implementing a One-to-Zero-or-One Relationship and a One-to-Many Relationship of the Same Class实现同一类的一对零或一关系和一对多关系
【发布时间】:2019-12-19 01:36:56
【问题描述】:

我在映射以下类时遇到问题。

我希望MainAboutPage 是可选的(一对零或一),而AboutSubPages 显然是一对多的。

理想情况下,我想将WebsiteId 属性保留在WebsitePage 类上。

public class Website
{
    public int Id { get; set; }

    public virtual WebsitePage MainAboutPage { get; set; }

    public ICollection<WebsitePage> AboutSubPages { get; set; }

}


public class WebsitePage
{
    public int Id { get; set; }

    public int WebsiteId { get; set; }

    public virtual Website Website { get; set; }
}

当我不使用流畅的映射时,我会得到

无法确定关系的主体端。多个添加的实体可能具有相同的主键。


当我使用这个流畅的映射时:

        modelBuilder.Entity<Wesbite>()
            .HasMany(x => x.AboutSubPages)
            .WithRequired(x => x.Website)
            .HasForeignKey(x => x.WebsiteId);

我明白了:

无法确定“Wesbite_AboutSubPages”关系的主体端。多个添加的实体可能具有相同的主键。


当我使用这个流畅的映射时:

        modelBuilder.Entity<Website>()
           .HasOptional(x => x.MainAboutPage)
           .WithRequired();

        modelBuilder.Entity<Wesbite>()
            .HasMany(x => x.AboutSubPages)
            .WithRequired(x => x.Website)
            .HasForeignKey(x => x.WebsiteId);

我明白了:

无法确定“Website_MainAboutPage”关系的主体端。多个添加的实体可能具有相同的主键。


当我使用这个流畅的映射时:

        modelBuilder.Entity<Website>()
           .HasOptional(x => x.MainAboutPage)
           .WithRequired(x => x.Website);

        modelBuilder.Entity<Wesbite>()
            .HasMany(x => x.AboutSubPages)
            .WithRequired(x => x.Website)
            .HasForeignKey(x => x.WebsiteId);

我明白了:

Wesbite_MainAboutPage_Target: : 多重性在关系“Website_MainAboutPage”中的角色“Wesbite_MainAboutPage_Target”中无效。因为从属角色属性不是关键属性,所以从属角色的多重性的上限必须是'*'。


我一直在无休止地阅读 MS 的配置示例:https://www.entityframeworktutorial.net/code-first/configure-one-to-one-relationship-in-code-first.aspxhttps://www.entityframeworktutorial.net/code-first/configure-one-to-many-relationship-in-code-first.aspx

我的大脑被腌制了,如果我遗漏了一些明显的东西,请原谅我。我真的很感激一些关于我想要的设置的指示。

提前致谢。

【问题讨论】:

    标签: asp.net-mvc entity-framework one-to-many ef-fluent-api fluent-interface


    【解决方案1】:

    我认为问题在于您没有足够的信息让 EF 区分关于网站的 AboutSubPages 和 MainAboutPage 引用。要在网站上为 MainAboutPage 建立 1..0/1 关系,您需要在网站表中声明 MainAboutPageId。

    modelBuilder.Entity<Website>()
       .HasOptional(x => x.MainAboutPage)
       .WithRequired(x => x.Website)
       .HasForeignKey(x => x.MainAboutPageId);
    

    或者您可以选择使用影子属性 (EF Core) 或 Map.MapKey (EF6) 来映射关系,而不在实体中公开 FK。 (推荐)

    具有 1..0/1 加上 1..many 的实体关系与相同相关实体的警告是,无法强制 MainAboutPage 实际上属于子集合。因为 1..0/1 依赖于从网页到子页面的 FK,所以没有强制要求子页面必须指向同一个网站。 EF 和 Database 非常乐意让 WebSite ID #1 指向具有 WebSite ID #2 的子页面。

    更好的方法可能是只查看维护 AboutSubPages 集合并将 PageOrder 数字唯一索引添加到 SubPage 实体。例如,“主”子页面将是具有最低 PageOrder 的页面。

    即选择一个网站的详细信息,它是关于页面的“主要”页面:

    var websites = context.Websites
        .Select(x => new WebsiteSummaryViewModel
        {
            Name = x.Name,
            AboutPageURL = x.AboutSubPages
                .OrderBy(a => a.PageOrder)
                .Select(a => a.Url)
                .FirstOrDefault()
        }).ToList();
    

    ... 举个例子。这确保了我们可以访问主页,同时确保网站考虑的唯一页面是分配给它的页面。可以在网站实体上设置未映射的属性以从嵌入式集合中返回“MainAboutPage”,但是我不建议使用未映射的属性,因为它们很容易滑入 Linq 表达式,并且 EF 将抛出异常或执行过早执行 (EF Core) 来解决这些问题。

    【讨论】:

    • 这是一个非常有启发性和启发性的答案,谢谢。只有一件事......它不允许我将.HasForeignKey(x =&gt; x.MainAboutPageId) 链接到.WithRequired()(ForeignKeyNavigationPropertyConfiguration 不包含 HasForeignKey 的定义)。不过我想我可以使用Map.MapKey
    • 相关问题,如果您觉得非常有帮助:entityframeworktutorial.net/code-first/…
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-30
    • 2014-01-11
    • 2015-05-04
    • 2018-09-27
    • 2019-07-25
    • 1970-01-01
    相关资源
    最近更新 更多