EF Code First - возврат записей из таблицы «многие ко многим» - PullRequest
0 голосов
/ 05 февраля 2019

Я пытаюсь получить все записи в таблице m: m плоско с помощью Entity Framework и LINQ.

Модели данных:

public partial class Group
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public Guid GroupId { get; set; }

    [StringLength(100)]
    public string Name { get; set; }

    public virtual ICollection<User> Users { get; set; }

}

public partial class User
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public Guid UserId { get; set; } = new Guid();

    [StringLength(100)]
    public string FirstName { get; set; }

    [StringLength(100)]
    public string LastName { get; set; }

    [StringLength(255)]
    public string DisplayName { get; set; }


    public virtual ICollection<Group> Groups { get; set; }

}

Вот запрос в SQLкоторый возвращает набор данных, который я ищу:

select g.GroupId, g.[Name], u.DisplayName, u.UserId 
from [Group] g, [User] u, [GroupUsers] gu
where g.GroupId = gu.Group_GroupId
and gu.User_UserId = u.UserId
order by g.[Name]

Вот то, что я пытаюсь в Linq, но я получаю ошибку самообращающегося цикла:

using (RequestContext ctx = new RequestContext())
{
     return ctx.Groups.SelectMany(x => x.Users).Include(x => x.Groups).ToList();
}

Кажется, это должно быть относительно просто, но я обнаружил, что m: m в Entity Framework может быть немного сложнее.Любая помощь будет оценена.

1 Ответ

0 голосов
/ 05 февраля 2019

Я рад, что вы определили свои многие-ко-многим как две виртуальные коллекции без указания таблицы соединений!

Вы понимаете, что если вы не получите "группы со своими пользователями ", но вместо того, чтобы запрашивать левое внешнее объединение групп и пользователей (вы называете это плоским способом), свойства группы будут повторяться снова и снова для каждого пользователя?

Но эй, этоваше решение, и вы должны убедить своего руководителя проекта, что лучше передавать одни и те же свойства группы сто раз, а не передавать их только один раз.

Вы были правы для левого внешнего соединения,вам нужно сделать SelectMany.Я не уверен, почему вы решили использовать Include вместо Select.

При запросе данных всегда используйте Выберите и выберите только те свойства, которые вы на самом деле планируетеиспользовать.Используйте Включить , только если вы планируете обновить извлеченные включенные данные.

Причина этого особенно значима в отношении «один ко многим».Если вы выбираете «Школы со своими учениками», а в Школе с идентификатором 4 - 1000 учеников, то вы знаете, что у каждого ученика этой школы будет внешний ключ со значением 4. Какая трата для передачи этого значения 4 более 1000 раз.!

Одна из перегрузок Enumerable.SelectMany имеет параметр resultSelector, который примет один Group и один User в качестве входных данных для создания результата.Эта версия идеально подходит для ваших нужд

var result = dbContext.Groups.SelectMany(
    group => group.Users,
    (group, user) => new
    {
        // Select the Group properties you plan to use
        GroupId = group.GroupId,
        GroupName = group.Name,
        ...

        // Select the User properties you plan to use
        UserId = user.UserId,
        UserName = user.DisplayName,
        ...
    })

    // if desired do some ordering
    .OrderBy(joinedItem => joinedItem.GroupName);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...