EF 核心一对多关系 HasOne().WithMany() 与 HasMany().WithOne()

问题描述 投票:0回答:3

假设我有以下 2 个型号:

public class Blog
{
    public int BlogId { get; set; }
    public string Url { get; set; }

    public List<Post> Posts { get; set; }
}

public class Post
{
    public int PostId { get; set; }
    public string Title { get; set; }
    public string Content { get; set; }

    public Blog Blog { get; set; }
}

现在如果我想在 DbContext 中配置模型关系,两者之间有什么区别:

modelBuilder.Entity<Post>()
            .HasOne(p => p.Blog)
            .WithMany(b => b.Posts);

modelBuilder.Entity<Blog>()
            .HasMany(b => b.Posts)
            .WithOne(p => p.blog);

如果有差异,那是什么?我应该写两个还是只写一个?

附注: 我必须定义外键吗?根据我对数据库的了解,没有外键就无法创建关系,但 EF 不要求您有外键字段。那么 EF 如何在不知道外键的情况下处理关系呢?它会导致性能下降或错误吗?

c# entity-framework asp.net-core
3个回答
13
投票

你是对的,你可以在 DbContext 中创建关系,而无需数据库中的外键。

还有:

WithOne一对一关系双方都有引用导航属性。它们遵循与一对多关系相同的约定,但在外键属性上引入了唯一索引,以确保只有一个依赖项与每个主体相关。

多对多:尚不支持没有实体类来表示连接表的关系。但是,您可以通过包含连接表的实体类并映射两个单独的一对多关系来表示多对多关系。

您只需要定义一个关系,因为在某些情况下,您将为没有导航属性(一个或集合)的父子关系创建一个关系。

对于您的示例:您添加博客 -> 帖子的关系,因为您在两个对象中都具有导航属性,这两行内容相同,但方式不同:

    博客 -> 帖子(父 -> 子)
  • 帖子 -> 博客(子 -> 家长)

5
投票
您可以在没有外键属性的情况下定义模型。但是,实体框架将引入影子属性,该属性将位于数据库中。

根据

文档

虽然建议在依赖实体类中定义外键属性,但这不是必需的。如果未找到外键属性,将引入一个名为

<navigation property name><principal key property name>

 的影子外键属性(有关更多信息,请参阅
影子属性)。


0
投票
就博客和帖子之间的关系如何运作而言,您提供的两种配置之间没有功能差异。两者达到相同的结果,定义 Blog 和 Post 之间的一对多关系,其中:

    一个博客可以有很多帖子。
  • 每个帖子都属于一个博客。
在 Entity Framework Core 中,由于 EF Core 如何推断关系,这些配置是等效的。以下是每种方法的细分:

首次配置

modelBuilder.Entity<Post>() .HasOne(p => p.Blog) .WithMany(b => b.Posts);
该配置从关系的Post端开始,指定:
•.HasOne(p => p.Blog):每个帖子都有一个博客。
•.WithMany(b => b.Posts):每个博客可以有很多帖子。

第二种配置

modelBuilder.Entity<Blog>() .HasMany(b => b.Posts) .WithOne(p => p.Blog);
这个配置是从Blog端开始的:
•.HasMany(b => b.Posts):每个博客可以有许多帖子。
•.WithOne(p => p.Blog):每个帖子都有一个博客。

要点 •两种配置都会在数据库中产生相同的一对多关系。 •Entity Framework Core 将以相同的方式解释关系并生成相同的 SQL 架构。

两者之间的选择通常基于可读性或偏好。如果您将“帖子”作为主要实体,那么从“帖子”进行配置可能会感觉更直观,对于“博客”反之亦然。

© www.soinside.com 2019 - 2024. All rights reserved.