#c# #entity-framework #asp.net-core
#c# #entity-framework #asp.net-core
Вопрос:
Как мне создать отношения «многие» между пользователем и подписчиками с помощью Code 1st Entity framework. Я попытался использовать следующий код
public class User : IdentityUser<int>
{
public string FirstName { get; set; }
public string LastName { get; set; }
public List<User> Followers { get; set; }
}
но, похоже, это не работает
Комментарии:
1. В каком смысле это не работает? Как вы можете сказать? Если есть ошибки, пожалуйста, поделитесь ими.
Ответ №1:
Чтобы создать отношения, ссылающиеся на себя, вам нужно будет явно настроить отношения. Для начала вам нужно будет назначить 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);
Вы можете использовать свойство Shadow для FK:
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 использовать столбец FollowingUserId в таблице без двух источников истинности для отношения в сущности. (пользователь.FollowingUserId против user.FollowingUserId.Идентификатор пользователя)
Оттуда вы также могли бы рассмотреть возможность создания однонаправленных отношений от подписчика к подписчику без сбора подписчиков. (Однонаправленные связи, как правило, легче поддерживать и вызывают меньше проблем, чем двунаправленные)
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 отдельно от «User» или такого, который отображается и связан друг с другом. В IdentityUser будут содержаться сведения, касающиеся аутентификации и авторизации, которые вы не захотите раскрывать или потенциально изменять при обновлении сведений о пользователях и их отношениях друг с другом. Например, если у нас есть «Blogger» и «User», где User равен аутентификации, а Blogger представляет пользователей системы в области отношений и общих сведений о персонаже, Blogger может содержать идентификатор пользователя (или у пользователя может быть BloggerId) без навигационной ссылки, чтобы избежать случайной утечки информации об аутентификации, если вынапример, мы должны были сериализовать сущности.