【问题标题】:How to Map Twitter follower/following type of relation in EF Core 5如何在 EF Core 5 中映射 Twitter 关注者/关注类型的关系
【发布时间】:2021-05-01 14:03:40
【问题描述】:

如何使用带有 Fluent API 的 EF Core 5 配置类似于 Twitter 关注和关注者类型的关系?我尝试了各种不同的配置方法,唯一能让它工作的方法是我忽略了用户实体上的导航属性。我目前正在将我的代码从 EF Core 2.1 迁移到 5。以下配置在早期工作。 (不知道是不是配置错误)

    public class User
    {
        public long Id { get; set; }

        public string Name { get; set; }

        public ICollection<UserFollower> Followers { get; set; }

        public ICollection<UserFollower> Following { get; set; }
    }

    public class UserFollower
    {
        public long UserId { get; set; }

        public User User { get; set; }

        public long FollowedById { get; set; }

        public User FollowedBy { get; set; }
    }

    public class UserFollowerConfiguration : IEntityTypeConfiguration<UserFollower>
    {
        public void Configure(EntityTypeBuilder<UserFollower> builder)
        {
            builder.HasKey(p => new { p.UserId, p.FollowedById });
            builder.HasOne(p => p.User)
                .WithMany(i => i.Followers)
                .HasForeignKey(i => i.UserId);
            builder.HasOne(p => p.FollowedBy)
                .WithMany(i => i.Following)
                .HasForeignKey(i => i.FollowedById);
        }
    }

此配置在保存到数据库时会引发错误。

SqlException: Violation of PRIMARY KEY constraint 'PK_UserFollower'. 
Cannot insert duplicate key in object 'dbo.UserFollower'. The duplicate key value is (111, 111).

即使尝试直接添加到 DbContext 并在其上调用 SaveChanges()

Context.Add(new UserFollower() {UserId = 222, FollowedById = 111});

将这种关系映射到 EF Core 5 的推荐方法是什么?请注意,我确实需要访问 UserFollowers 表,而无需通过用户的导航属性。

编辑#1

以下是 DbContext 的OnModelCreating()

    protected override void OnModelCreating(ModelBuilder builder)
    {
        base.OnModelCreating(builder);
        builder.ApplyConfigurations(typeof(DbContext).Assembly);
        
        /*few configurations unrelated to UserFollower entity*/
    }

用户实体有如下配置,

    builder.HasKey(i => i.Id);
    builder.Property(i => i.Id).ValueGeneratedOnAdd();

【问题讨论】:

  • 配置没问题。显然您在应用(不确定是什么)更改时做错了 - 您最好显示该代码。
  • 代码完全没问题。似乎问题出在其他地方。
  • @IvanStoev 我已经用配置应用代码更新了问题。

标签: c# entity-framework-core ef-code-first ef-fluent-api ef-core-5.0


【解决方案1】:

尝试像这样配置它。

builder.Entity<User>().HasMany(s => s.Followers)
    .WithOne(f => f.FollowedBy);
builder.Entity<User>().HasMany(s => s.Following)
    .WithOne(f => f.);

另外,UserFollower 表缺少 PK,我不知道是否在某处生成了 Id。如果不是,也许这就是为什么它试图错误地使用FollowedById 作为键,而是为UserFollower 表定义一个ID 并查看。

public class UserFollower
{
    public long Id {get;set;} 

    public long UserId { get; set; }

    public User User { get; set; }

    public long FollowedById { get; set; }

    public User FollowedBy { get; set; }
 }

即使这可行,我还是建议您更改模型的结构,它对于您描述的 twitter 要求看起来模棱两可。如果我查询Userfollowers

var userFollowers = _context.UserFollowers.ToList();

对于列表中的每个结果,我无法判断用户是否正在关注或被关注。您可以将模型更改为这些模型;

public class User
{
    public long Id { get; set; }

    public string Name { get; set; }

    public ICollection<UserFollower> Followers { get; set; }

    public ICollection<UserFollowing> Following { get; set; }
}

public class UserFollower
{
    public long UserId { get; set; }

    public User User { get; set; }

    public long UserFollowingMeId { get; set; }

    public User UserFollowingMe { get; set; }
}
public class UserFollowing
{
    public long UserId { get; set; }

    public User User { get; set; }

    public long UserIAmFollowingId { get; set; }

    public User UserIAmFollowing { get; set; }
}

这样,每个人都知道当他们检查UserFollowings 表时,UserId 是关注者的ID,反之亦然UserFollowers 表。如果我在系统中有一个 8 的 ID,我可以像这样查询我的关注者和我关注的人;

var myFollowers = _context.UserFollowers.Where(UserId = 8);
var peopleIFollow = _context.UserFollowing.Where(UserId = 8);

【讨论】:

  • UserFollower 确实有一个复合主键。不确定是否有 2 个单独的表来存储相同的信息是这里的解决方案。
  • @JudeVajiraGunasekera 您是否尝试过答案第一部分中的配置?而且我从未说过第二部分是解决您问题的方法。我只是说这将是满足追随者要求的更好方法,因为如果我查看您的 UserFollower 表的当前状态,我无法判断 FollowedBy 列中的用户是否是我关注的用户或一个关注我的用户。
  • 是的,就像您提到的那样,我已经尝试从用户实体端对其进行配置,但它仍然会像问题中那样弄乱SaveChanges() 上的值。是的,我同意,命名一目了然。
  • 有可能您已经在 UserFollower 表中拥有UserId = 111FollowedById = 111 的记录。然后,您现在尝试创建具有相同值的新记录,重复。由于您没有传统的主键,因此数据库无法知道差异,它只是尝试创建另一个 (111, 111) 复合键,并引发重复错误。尝试添加主键并查看
  • 当我尝试添加 (222,111) 时,它不应该给出错误提示 (111,111) 密钥冲突。是的,冲突来了,因为即使我上次尝试添加它也添加了 (111,111) 而不是 (222,111)
猜你喜欢
  • 2013-10-02
  • 2015-10-26
  • 2021-05-01
  • 1970-01-01
  • 1970-01-01
  • 2016-06-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多