【问题标题】:How to implement an self referencing many to many relationship with Entity Framework Core 1.1?如何使用 Entity Framework Core 1.1 实现自引用多对多关系?
【发布时间】:2017-06-15 16:53:27
【问题描述】:

我正在按照本教程使用 EF Core 1.1 实现我的友谊系统:http://www.codedodle.com/2014/12/social-network-friends-database.html

Friendship.cs

public class Friendship
{
    public Guid ApplicationUserId { get; set; }
    public ApplicationUser ApplicationUser { get; set; }

    public Guid FriendId { get; set; }
    public ApplicationUser Friend { get; set; }

    public StatusCode Status { get; set; }

    public Guid ActionUserId { get; set; }
    public ApplicationUser ActionUser { get; set; }

    public byte[] Timestamp { get; set; }
}

public enum StatusCode
{
    Pending = 0,
    Accepted = 1,
    Declined = 2,
    Blocked = 3
}

ApplicationUser.cs

public class ApplicationUser : IdentityUser<Guid>
{
    ...

    public ICollection<Friendship> FriendRequestsMade { get; set; }

    public ICollection<Friendship> FriendRequestsAccepted { get; set; }

    public byte[] Timestamp { get; set; }
}

MyDbContext.cs

public class SocialCircleContext : IdentityDbContext<ApplicationUser, Role, Guid>
{

     builder.Entity<Friendship>()
        .HasIndex(x => new { x.ApplicationUserId, x.FriendId })
        .IsUnique();

     builder.Entity<Friendship>()
        .HasOne(x => x.ApplicationUser)
        .WithMany(y => y.FriendRequestsMade)
        .HasForeignKey(x => x.ApplicationUserId).OnDelete(DeleteBehavior.Restrict);

    builder.Entity<Friendship>()
        .HasOne(x => x.Friend)
        .WithMany(y => y.FriendRequestsAccepted)
        .HasForeignKey(x => x.FriendId);         
}

添加迁移 InitialMigration 的结果

无法确定“ApplicationUser”类型的导航属性“Friendship.ActionUser”所代表的关系。要么手动配置关系,要么从模型中忽略此属性。

此外,随着 EF Core 的快速发展,我找到了许多不同的方法来做到这一点。我不确定我的自引用多对多关系的实现,有人可以给我一些建议吗?

  1. 如何定义 Friendship.ActionUser 和 ApplicationUser 之间的关系?
  2. 对于实现这种自引用多对多关系的正确方法有什么建议吗? EF Core 发展很快,我在网上找到了很多不同的方法,但它们似乎已经过时了

谢谢! :)

【问题讨论】:

标签: c# asp.net-core many-to-many entity-framework-core self-referencing-table


【解决方案1】:

理想情况下,一旦关系发现中的歧义得到解决,EF 应该按照惯例创建其余的关系,但由于错误而不会发生。 (提交Bug

您的模型类对于您正在尝试做的事情是正确的。要让 EF 成功构建模型,需要填补的部分很少。

首先,让我们解决您看到的异常。 您的 ApplicationUser 类有 2 个指向 Friendship 的集合导航。而Friendship 类有3 个参考导航指向ApplicationUser。虽然 EF Core 在按约定创建关系方面做得很好,但在这种情况下,它不知道如何创建导航-反向导航对。因此需要通过注解/流利的 API 进行用户输入。在您的情况下,您正在使用 fluent API 创建 2 个关系,每侧使用 2 个导航。这让我们只有导航Friendship.ActionUser,没有任何关系。在这一点上,EF Core 对如何从中创建关系没有任何困惑,但由于存在错误,它没有这样做。这意味着您必须使用 fluent API 手动配置此关系。

builder.Entity<Friendship>().HasOne(e => e.ActionUser).WithOne().HasForeignKey<Friendship>(e => e.ActionUserId);

这将创建一对一的关系。您可以使用HasOne(...).WithMany() 创建一对多关系。

这将使您摆脱上述错误。现在您将看到另一个错误,因为类 Friendship 没有定义主键。虽然文章说创建唯一索引,但对于多对多连接表,连接表配置为具有复合 PK,以便它可以表示唯一连接。所以不要像上面那样调用HasIndex,你应该使用下面的代码。

builder.Entity<Friendship>().HasKey(e => new { e.ApplicationUserId, e.FriendId });

在上面的代码之后,您可以删除HasIndex 调用,因为 PK 始终是唯一的,并且大多数数据库都为 PK 定义了索引。

通过上述更改,您的模型应该可以正常工作了。

其他事情:由于Friendship.ActionUser 定义的关系对于它是一对一或一对多来说有点模棱两可,也许它根本不应该是一个关系。 ActionUserId 应该采用ApplicationUserIdFriendId 的值之一,您可以通过选择其中一个导航轻松访问ActionUser。您可以在 EF 中创建 ActionUser [NotMapped] 并使用基于 ActionUserId 返回的值 ApplicationUser/Friend 进行计算。虽然这些是设计选择。没有正确或错误的方法。应该使用最有意义且对您的消费方式最有帮助的那个。

【讨论】:

    猜你喜欢
    • 2017-02-27
    • 2020-07-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-12-10
    • 2019-06-18
    • 2021-10-29
    相关资源
    最近更新 更多