c# - 如何使用 Entity Framework Core 1.1 实现自引用多对多关系?

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

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

友谊.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);         
}

Add-Migration InitialMigration 的结果

Unable to determine the relationship represented by navigation property 'Friendship.ActionUser' of type 'ApplicationUser'. Either manually configure the relationship, or ignore this property from the model.

此外,由于 EF Core 发展迅速,我发现了很多不同的方法来实现这一点。我不确定我如何实现自引用多对多关系,有人可以给我一些建议吗?

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

谢谢! :)

最佳答案

理想情况下,一旦关系发现中的歧义得到解决,EF 应该按照约定创建其余的关系,但由于错误而没有发生。 (归档 Bug )

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

首先,让我们解决您看到的异常。 您的 ApplicationUser 类有 2 个指向 Friendship 的集合导航。 Friendship 类有 3 个引用导航指向 ApplicationUser。虽然 EF Core 在按照约定创建关系方面做得很好,但在这种情况下,它不知道如何创建导航-反向导航对。因此需要通过注释/流畅的 API 进行用户输入。在您的情况下,您正在使用流畅的 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 进行计算。尽管这些是设计选择。没有正确或错误的方法。无论哪种方式最有意义并且对您的消费方式帮助最大,都应该使用它。

关于c# - 如何使用 Entity Framework Core 1.1 实现自引用多对多关系?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44572936/

相关文章:

c# - 发布时的 TransformXml Web.config

c# - 如何使用反射来查找实现特定接口(interface)的属性?

asp.net-core - 在 RavenDB .net 中将 IDocumentStore 设置为静态变量

postgresql - 根据计数限制插入的通用触发器

java - Odoo 请求中的 Many2Many 字段插入在 Android 中不起作用

c# - 我如何(从 SalesOrderEntity)检索送货地址?

c# - 具有公共(public)字段的不同类之间的 IEnumerable.Except()

c# - .net标准类库-不支持分布式事务错误

.net - 丢失版本和工具 : . NET Core、Core Tools、dotnet Core CLI,

postgresql - PostgreSQL 中与自身的多对多关系