Как создать функцию добавления друга между двумя отдельными учетными записями пользователей в одной таблице в asp. net основных идентификаторах - PullRequest
0 голосов
/ 04 августа 2020

Я разрабатываю мини-приложение для социальных сетей и использую ASP. NET Identity для создания учетных записей пользователей и управления ими. Я хочу добавить еще одну учетную запись пользователя в качестве друга к своей учетной записи. Я мог бы успешно это сделать, но проблема в том, что когда я проверял учетную запись добавленного друга, в его списке друзей не было обновлений. Он пуст.

Вот мой класс User, унаследованный от 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; }
}

Мой класс DbContext,

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; }
}

Метод моего класса контроллера для добавления друга,

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("/");
    }

Ответы [ 2 ]

0 голосов
/ 05 августа 2020

Я думаю, вы неправильно моделируете свою сущность. Поскольку пользователь может иметь список друзей, а также быть другом других пользователей, я думаю, вам нужно зафиксировать последнюю часть в модели.

Так как это отношения «многие ко многим», и EF Core до сих пор не поддерживает без объявления сущности для представления объединенной таблицы , вам также необходимо определить эту сущность:

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; }
}

И затем вам нужно настроить их отношения :

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; }
}

Примечание OnDelete(DeleteBehavior.Restrict). Вы должны установить для него значение, отличное от DeleteBehavior.Cascade, которое является значением по умолчанию для предотвращения каскадного удаления.

Отказ от ответственности: я написал все вручную. Никогда не проверяйте это.

0 голосов
/ 04 августа 2020

Вам нужно будет использовать функцию Include.

// What you have is fine.
var friend = context.Users.Select ( u => u == id );

// this is what needs to occur in await userManager.GetUserAsync(this.User);
// Without the include the Navigation Property will not be tracked.
var user = context.Users
    .Select ( u => u == id )
    .Include ( u => u.Friends );

user.Friends.Add ( friend );
context.SaveChanges ();

Проверьте загрузку связанных данных. https://docs.microsoft.com/en-us/ef/core/querying/related-data

РЕДАКТИРОВАТЬ:

Взгляните на этот пост, это дубликат этого.

Многие-к- многие отношения со ссылками на себя

РЕДАКТИРОВАТЬ 2: Итак, проблема, с которой вы столкнулись, заключается в том, что вы все еще пытаетесь смоделировать это как одну таблицу. Подумайте, как это будет структурировано в базе данных SQL. Как может одна таблица содержать коллекцию (Друг) в одном столбце? Чтобы выполнить sh это, мы создадим новую таблицу для моделирования отношений между пользователями приложений.

public class Friendship 
{
    // Foreign Key
    Int32 MeId { get; set; }

    // Foreign Key
    Int32 FriendId { get; set; }

    // Navigation Property
    AppUser Me { get; set; }

    // Navigation Property
    AppUser Friend { get; set; }
}
public class AppUser : IdentityUser
{
    public AppUser()
    {
        this.Friends = new HashSet<AppUser>();
    }
    
    // Primary Key. Is this defined in IdentityUser?
    public int Id { get; }
    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; }

    // This is considered a Navigation Property 
    public ICollection<Friendship> Friends { get; set; }
}
protected override void OnModelCreating(ModelBuilder builder)
{
    base.OnModelCreating(builder);
    builder.Entity<AppUser>(x =>
    {
        x.HasPrimaryKey ( x => x.Id );
    });

    builder.Entity<Friendship>( f =>
    {
        f.HasKey ( f => new { f.MeId, f.FriendId } );
        f
            .HasOne( f => f.Me )
            .WithMany ( u => u.Friends )
            .HasForeignKey( f => f.MeId );

        f
            .HasOne( f => f.Friend )
            .WithMany ( u => u.Friends )
            .HasForeignKey( f => f.FriendId );
    });        
}

На этом этапе вы должны иметь возможность запрашивать объединенную таблицу для дружбы.

public void AddFriend ( AppUser user, AppUser friend ) {
    var trackedUser = context.AppUsers
         .Select ( u => u.Id == user.Id )
         .Include ( u => u.Friends );          
         .FirstOrDefault ();

   trackedUser.Friends.Add ( new Friendship () { 
       MeId = user.Id, 
       FriendId = friend.Id 
   });
   context.SaveChanges ();
}
...