EF Core 5.0 中的多对多关系是不是可以配置为仅保留一个导航属性(在一侧)?

Posted

技术标签:

【中文标题】EF Core 5.0 中的多对多关系是不是可以配置为仅保留一个导航属性(在一侧)?【英文标题】:Can many-to-many relationships in EF Core 5.0 be configured keeping just one navigation property (on one side)?EF Core 5.0 中的多对多关系是否可以配置为仅保留一个导航属性(在一侧)? 【发布时间】:2021-10-07 14:49:31 【问题描述】:

我已经使用以下代码配置了我的 DbContext (EF Core 5.0):

protected override void OnModelCreating(ModelBuilder modelBuilder)

    modelBuilder.Entity<User>()
        .HasMany(p => p.Roles)
        .WithMany(p => p.Users)
        .UsingEntity<Dictionary<string, object>>("UsersToRoles",
            x => x.HasOne<Role>().WithMany().HasForeignKey("UserId"),
            x => x.HasOne<User>().WithMany().HasForeignKey("UserId"),
            x => x.ToTable("UsersToRoles"));

    modelBuilder.Entity<Role>()
        .ToTable("Roles")
        .Property(r => r.Application)
        .IsRequired();

    base.OnModelCreating(modelBuilder);

问题是我不希望Role 实体持有Users 的集合。我保留它是因为 EF Core 需要它来配置多对多关系。

有没有办法创建相同的关系,但不必定义Role.Users 导航属性?

【问题讨论】:

看起来这可能是不可能的,但在这里提交和跟踪作为增强:github.com/dotnet/efcore/issues/3864 如果您绝对想要阻止Role 了解用户,那么您必须通过使用显式联结类来解决问题。但这不是你要问的,所以我不认为这是一个答案。 【参考方案1】:

简短的回答是——你在问什么是想要的,但还不支持,正如官方当前Many-to-many部分开头所明确指出的(虽然没有足够强调,但没有人喜欢强调限制) EF Core 文档(重点是我的):

多对多关系两边都需要一个集合导航属性

在原始跟踪项Many-to-many (skip) navigation properties #19003的末尾也可以看到基本相同的问题

您好,有没有办法避免为其中一个实体定义属性? 例如

builder.HasMany(p => p.Tags).WithMany(); // notice no parameter in `WithMany`

团队的回应是

还没有#3864

直接指向Support unidirectional many-to-many relationships through shadow navigations #3864,这是相应的当前未解决问题,并且似乎计划发布 6.0。

至于为什么,只有团队成员才能回答这个问题,但很可能是因为通常没有足够的时间在有限的时间范围内完成交付特定版本的任务。用于实现实际功能的全新(但不完全)概念(跳过导航),有很多可能的改进,如 Support non-many-to-many skip navigations #21673、有问题的和许多其他的 - 您可以在此处查看当前列表 Improve many-to-many, skip navigations, and indexer properties #22960 .再加上技术上的困难,缺乏影子导航属性支持(尽管这并不能阻止其他类型的关系,即使在任何一方都没有导航也可以配置(这将如何有用是另一回事))等。

最后一点,以防您正在寻找解决方法/克服当前限制的方法。我通常喜欢超越 EF Core 的限制,但首先我看不到值(我个人认为导航属性更像是表示 LINQ 查询中的关系而不是存储的元数据),并且还试图克服它直接使用内部元数据 API 以及丑陋的代码只会导致不同的运行时异常,这对我来说证明了当前代码确实依赖于“反向”导航,并且在很多地方都受到限制。

因此,您至少需要一个私有的 ICollection&lt;User&gt; Users 属性或字段,从序列化中排除并流畅配置

modelBuilder.Entity<User>().HasMany(e => e.Roles).WithMany("Users");

并接受它将从 EF Core 导航修复中填充的事实。或者更好的是,只需使用公共导航属性并等待该功能的正式实施。

【讨论】:

我读到private ICollection&lt;User&gt; Users 会破坏显式加载——但我对该配置的了解还不够,无法确定。否则,我相信这是正确的答案。它引用了 #3864 和阴影导航属性,这是我在设置赏金后发现的。谢谢!

以上是关于EF Core 5.0 中的多对多关系是不是可以配置为仅保留一个导航属性(在一侧)?的主要内容,如果未能解决你的问题,请参考以下文章

定义引用同一个表的多对多关系(EF7/core)

使用流利的 api EF Core 5 的多对多关系

如何直接填充由 EF Core 生成的多对多关系连接表?

EF Core中的多对多映射如何实现?

EF Core中如何设置数据库表自己与自己的多对多关系

如何过滤 EF Core 中的多对多联接