I am developing a mini social media web app and I use ASP.NET Identity to create and manage user accounts. I want to add another user account as a friend to my account. I could succesfully do that but the problem is when I checked my added friend's account, there is no update in his friends list. It's empty.
Here is my User class inherited from IdentityUser,
public class AppUser : IdentityUser
{
public AppUser()
{
this.Friends = new HashSet<AppUser>();
}
public int Age { get; set; }
public string Sex { get; set; }
public string City { get; set; }
public string Education { get; set; }
public string Description { get; set; }
public string? FriendOfUserId { get; set; }
public virtual AppUser FriendOf { get; set; }
public ICollection<AppUser> Friends { get; set; }
}
My DbContext class,
public class ApplicationDbContext : IdentityDbContext<AppUser>
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options)
{
}
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
builder.Entity<AppUser>(x =>
{
x
.HasMany(x => x.Friends)
.WithOne(x => x.FriendOf)
.HasForeignKey(x => x.FriendOfUserId);
});
}
public DbSet<AppUser> Users { get; set; }
}
My Controller Class method to add friend,
public async Task<IActionResult> AddFriend(string id)
{
var addFriend = await context.Users.Include(u => u.Friends).FirstOrDefaultAsync(u => u.Id == id);
var user = await userManager.GetUserAsync(this.User);
var u = await context.Users.Include(u => u.Friends).FirstOrDefaultAsync(u => u.Id == user.Id);
user.FriendOf = addFriend;
user.Friends.Add(addFriend);
await context.SaveChangesAsync();
return Redirect("/");
}
I think you're not modeling your entity correctly. Since an user can have a list of friends, and also be a friend of other users, I guess you need to capture the latter part in the model.
Since this is a many-to-many relationship, and EF Core still hasn't supported it without declaring an entity to represent the join table, you need to defind that entity as well:
public class AppUser : IdentityUser
{
public int Age { get; set; }
public string Sex { get; set; }
public string City { get; set; }
public string Education { get; set; }
public string Description { get; set; }
public ICollection<AppUserFriendship> FriendsOf { get; set; }
public ICollection<AppUserFriendship> Friends { get; set; }
}
public class AppUserFriendship
{
public string UserId { get; set; }
public AppUser User { get; set; }
public string UserFriendId { get; set; }
public AppUser UserFriend { get; set; }
}
And then you need to configure their relationships:
public class ApplicationDbContext : IdentityDbContext<AppUser>
{
...
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
builder.Entity<AppUserFriendship>(b =>
{
b.HasKey(x => new { x.UserId, x.UserFriendId };
b.HasOne(x => x.User)
.WithMany(x => x.Friends)
.HasForeignKey(x => x.UserId)
.OnDelete(DeleteBehavior.Restrict);
b.HasOne(x => x.UserFriend)
.WithMany(x => x.FriendsOf)
.HasForeignKey(x => x.UserFriendId)
.OnDelete(DeleteBehavior.Restrict);
});
}
public DbSet<AppUser> Users { get; set; }
}
Note OnDelete(DeleteBehavior.Restrict)
. You have to set it to something other than DeleteBehavior.Cascade
which is the default to prevent the cascade deletion.
Disclaimer: I wrote all by hand. Never test it.