首页 > 解决方案 > 如何使用 Code 1st Entity 框架在用户和关注者之间建立关系

问题描述

如何使用 Code 1st Entity 框架在用户和关注者之间创建多对关系。我尝试使用以下代码

  public class User : IdentityUser<int>
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }

        public List<User> Followers { get; set; }
      
    }

但它似乎不起作用

标签: c#entity-frameworkasp.net-core

解决方案


要创建自引用关系,您需要显式配置该关系。首先,您需要为追随者指定一个可以为空的 FK 以链接回主用户。将其声明为 FK 属性将类似于:

public class User : IdentityUser<int>
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    
    public int? FollowingUserId { get; set; }
    public virtual User FollowingUser { get; set; }
    public virtual ICollection<User> Followers { get; set; }      
}

从那里您需要配置映射。使用 modelBuilder 类似于:

modelBuilder.Entity<User>()
    .HasOptional(x => x.FollowingUser)
    .WithMany(x => x.Followers)
    .HasForeignKey(x => x.FollowingUserId);

您可以为 FK 使用 Shadow 属性:

public class User : IdentityUser<int>
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    
    public virtual User FollowingUser { get; set; }
    public virtual ICollection<User> Followers { get; set; }      
}

modelBuilder.Entity<User>()
    .HasOptional(x => x.FollowingUser)
    .WithMany(x => x.Followers)
    .HasForeignKey("FollowingUserId");

这告诉 EF 使用表中的 FollowUserId 列,而没有实体中关系的两个真实来源。(user.FollowingUserId 与 user.FollowingUserId.UserId)

从那里您还可以考虑在没有 Followers 集合的情况下使关系从关注者到关注的单向。(单向关系通常比双向关系更容易维护并且导致的问题更少)

public class User : IdentityUser<int>
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    
    public virtual User FollowingUser { get; set; }
}

modelBuilder.Entity<User>()
    .HasOptional(x => x.FollowingUser)
    .WithMany()
    .HasForeignKey("FollowingUserId");

您仍然可以获得特定用户的关注者列表:

var followers = context.Users.Where(x => x.FollowingUser.UserId == userId);

虽然它可以使某些类型的查询更加复杂,例如如果您想列出所有用户及其关注者的数量。(需要一个GroupBy没有导航参考的 EF 来处理查询)

我建议的另一点是将 IdentityUser 与“用户”分开,或者这样才能显示并相互关联。IdentityUser 将包含与身份验证和授权相关的详细信息,在更新有关用户及其相互关系的详细信息时,您不希望暴露或可能被篡改。例如,如果我们有一个“Blogger”和一个“User”,其中 User 等于 Authentication,而 Blogger 代表关系范围和一般角色详细信息范围内的系统用户,Blogger 可以包含一个 UserId(或 User 可以有一个 BloggerId),而没有例如,如果您要序列化实体,导航参考以避免意外泄漏身份验证信息。


推荐阅读