问题描述
如何使用 EF Core 5 和 Fluent API 配置类似于 Twitter 关注和关注者类型的关系?我尝试了各种不同的配置方法,唯一能让它工作的方法是忽略 User 实体上的导航属性。我目前正在将我的代码从 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();
解决方法
尝试像这样配置它。
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
表,反之亦然。如果我在系统中的Id为8,我可以这样查询我的关注者和我关注的人;
var myFollowers = _context.UserFollowers.Where(UserId = 8);
var peopleIFollow = _context.UserFollowing.Where(UserId = 8);