Entity Framework — отношение «один ко многим» возвращает неверное количество записей

#.net #entity-framework #entity-framework-core

#.net #entity-framework #entity-framework-core

Вопрос:

Сущность «Пользователь» имеет отношение «один ко многим» к сущности «Член группы».

 public class User
{
    #region Public properties
    [Key]
    [Column("id")]
    public int Id { get; set; }
    ...
    public virtual ICollection<GroupMember> GroupMembers { get; set; }

    public virtual ICollection<Profile> Profiles { get; set; }
    #endregion
}
  
 public class GroupMember
{
    #region Public properties
    [Required]
    [Column("groupid")]
    public int GroupId { get; set; }

    public virtual Group Group { get; set; }

    [Required]
    [Column("userid")]
    public int UserId { get; set; }

    public virtual User User { get; set; }

    [Required]
    [Column("lu_user")]
    public int LuUser { get; set; }

    [Required]
    [Column("lu_date")]
    public DateTime LuDate { get; set; }
    #endregion
}
  

В классе UserDbContext я настроил связь следующим образом:

 protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<GroupMember>()
        .HasKey(x => x.UserId);

    modelBuilder.Entity<GroupMember>()
        .HasOne(x => x.User)
        .WithMany(x => x.GroupMembers)
        .HasForeignKey(x => x.UserId);
}
  

При выполнении запроса:

 var user = _dbContext.Users
                .Include(u => u.Profiles)
                .Include(u => u.GroupMembers)
                    .ThenInclude(gm => gm.Group)
                .Where(u => u.Id == id)
                .Select(u => u)
                .SingleOrDefault();
  

Поле «Члены группы» должно содержать семь записей. Результатом запроса является одна запись для поля «Члены группы».

Я не понимаю, почему я не получаю правильное количество записей для отношения.

Ответ №1:

С помощью этого свободного API

 modelBuilder.Entity<GroupMember>()
    .HasKey(x => x.UserId);
  

вы сообщаете EF, что UserId столбец GroupMember таблицы уникален, что делает связь фактически однозначной. Вот почему вы получаете только одну запись на пользователя, даже если у вас есть свойство навигации по коллекции.

Поскольку GroupMember объект выглядит как объект объединения, используемый в отношениях «многие ко многим» (которые, как мы знаем, могут быть просмотрены как многие отношения «один ко многим»), скорее всего, ему нужен составной первичный ключ, например

 modelBuilder.Entity<GroupMember>()
    .HasKey(x => new { x.GroupId, x.UserId });
  

Этого должно быть достаточно, если вы сопоставляете существующую базу данных (поскольку вы ожидаете несколько записей из запроса, следовательно, вы знаете, что таблица существует и содержит несколько записей для каждого пользователя, что было бы невозможно, если UserId бы она была уникальной).

Но на всякий случай, если вы используете подход code first с миграциями, обязательно создайте и примените новую миграцию после выполнения вышеуказанного изменения.

Комментарии:

1. Большое вам спасибо за то, что помогли мне понять проблему.

Ответ №2:

Пожалуйста, не создавайте / не устанавливайте DbContext самостоятельно. Используйте команду Scaffold-Dbcontext для автоматического создания DbContext для вас.

 Scaffold-DbContext "Server=(localdb)mssqllocaldb;Database=Blogging;Trusted_Connection=True;" Microsoft.EntityFrameworkCore.SqlServer -OutputDir Models