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

Posted

技术标签:

【中文标题】EF 核心一对多关系 HasOne().WithMany() vs HasMany().WithOne()【英文标题】:EF core one-to-many relationships HasOne().WithMany() vs HasMany().WithOne() 【发布时间】:2017-02-08 11:16:27 【问题描述】:

假设我有以下 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 如何在不知道外键的情况下处理关系呢?它会导致性能下降或错误吗?

【问题讨论】:

learnentityframeworkcore.com/configuration/… 今天可能会有所帮助 【参考方案1】:

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

还有:

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

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

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

对于您的示例:您为 Blog -> Posts 添加了一个关系,因为您在两个对象中都有导航属性,这两行相同但方式不同:

博客 -> 帖子(父级 -> 子级) 帖子 -> 博客(子 -> 父)

【讨论】:

那么你是说这两种方法之间没有区别,无论哪种方式我都可以以同样的方式使用模型?但是使用 HasOne().WithMany 更好? 在这种情况下没有更好的方法,它们只是创建两个对象之间关系的不同方法,通常是从子对象到父对象的映射 "您可以在 DbContext 中创建关系,而无需在数据库中使用外键。"这是不正确的。 EF 将引入一个影子属性,该属性不会出现在您的模型中,但会出现在数据库中。 感谢您的反馈,无论如何我的意思是从应用程序方面来说,我们并不关心数据库中是否存在该关系的约束,有时有人会问我们是否需要先定义数据库端的关系 @H.Herzl 恐怕 EFCore 确实假设数据库中始终存在约束,因为当使用 .OnDelete(DeleteBehavior.Cascade) 配置关系时,行为只会引起注意跟踪的依赖实体,而未跟踪的实体应该由级联删除外键神奇地处理。请参阅这篇文章并注意以下 cmets:docs.microsoft.com/en-us/ef/core/saving/cascade-deleteIMO,让 ORM 对数据库结构和约束施加某些期望是一个非常短视的设计决定。【参考方案2】:

您可以在没有外键属性的情况下定义模型。但是,Entity Framework 将引入一个影子属性,该属性将在数据库中。

根据documentation:

虽然建议在依赖实体类中定义外键属性,但这不是必需的。如果未找到外键属性,则会引入名为 &lt;navigation property name&gt;&lt;principal key property name&gt; 的影子外键属性(有关详细信息,请参阅 Shadow Properties)。

【讨论】:

它不会在“数据库中”,而是在 EF Core 中的实体定义中。 它肯定会在数据库中。同样,根据文档:Shadow properties are useful when there is data in the database that should not be exposed on the mapped entity types. They are most often used for foreign key properties, where the relationship between two entities is represented by a foreign key value in the database, but the relationship is managed on the entity types using navigation properties between the entity types. Shadow 属性是实体框架的概念,而不是数据库的概念。所以不,它们不在“数据库中”。我提到这一点只是为了让研究这个主题的人清楚。 实际上,如果您尝试我之前评论中链接的 EF Core 文档中的示例,您会发现 EF 将在表 Posts 上创建一个列 BlogId 'in the database'。也许我们在谈论不同的东西,但是 shadow 属性在数据库中肯定会有对应的列。 我相信“影子属性”意味着您不会在类型本身上看到该属性。但它会在数据库中。

以上是关于EF 核心一对多关系 HasOne().WithMany() vs HasMany().WithOne()的主要内容,如果未能解决你的问题,请参考以下文章

EF 核心。两个实体(表)之间的多个一对一或零关系

大叔最新课程~EF核心技术剖析

使用 EF 核心将多个关系数据添加到 SQL Server

EF Core 一对一 一对多 多对多 关系定义

EF Core中通过Fluent API配置一对多关系

EF基础知识小记五(一对多多对多处理)