3

我正在按照本教程使用 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
}

应用程序用户.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 发展迅速,我在网上找到了很多不同的方法,但它们似乎已经过时了

谢谢!:)

4

1 回答 1

2

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

您的模型类对于您正在尝试做的事情是正确的。要使 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对于它是一对一或一对多来说有点模棱两可,也许它根本不应该是一个关系。ApplicationUserIdActionUserId 应该采用or的值之一FriendId,您可以通过选择其中一个导航轻松访问 ActionUser。您可以[NotMapped]在 EF 中创建 ActionUser 并使用ApplicationUser/Friend基于返回的值进行计算ActionUserId。虽然这些是设计选择。没有正确或错误的方法。无论哪种方式最有意义并且对您的消费方式最有帮助,都应该使用它。

于 2017-06-17T01:22:42.950 回答