Подтвердить что ты не робот

Linq To Entities - как фильтровать дочерние объекты

У меня есть сущности Group и User.
объект Group имеет свойство Users, которое является списком пользователей.
Пользователь имеет свойство с именем IsEnabled.

Я хочу написать запрос linq, который возвращает список Group s, который состоит только из User, чей IsEnabled является истинным.

так, например, для данных, подобных ниже
AllGroups
Группа A
Пользователь 1 (IsEnabled = true)
Пользователь 2 (IsEnabled = true)
Пользователь 3 (IsEnabled = false)

Группа B
Пользователь 4 (IsEnabled = true)
Пользователь 5 (IsEnabled = false)
Пользователь 6 (IsEnabled = false)

Я хочу получить
FilteredGroups
Группа A
Пользователь 1 (IsEnabled = true)
Пользователь 2 (IsEnabled = true)

Группа B
Пользователь 4 (IsEnabled = true)

Я попробовал следующий запрос, но Visual Studio говорит мне, что
[Свойству или индексу "Пользователи" нельзя назначить - он доступен только для чтения]

FilteredGroups = AllGroups.Select(g => new Group()
                    {
                        ID = g.ID,
                        Name = g.Name,
                        ...
                        Users = g.Users.Where(u => u.IsInactive == false)
                    });

Благодарю вас за помощь!

4b9b3361

Ответ 1

Мне удалось это сделать, перевернув запрос вверх дном:

var users = (from user in Users.Include("Group")
             where user.IsEnabled
             select user).ToList().AsQueryable()

from (user in users
      select user.Group).Distinct()

Используя ToList(), вы принудительно завершаете обратную пересылку в базу данных, которая требуется, поскольку в противном случае отложенное выполнение происходит на пути. Второй запрос только повторно заказывает извлеченные данные.

Примечание. Возможно, вы не сможете впоследствии обмануть свои объекты!

Ответ 2

Нет никакого "приятного" способа сделать это, но вы можете попробовать это: выполнить проект как Group, так и отфильтрованный Users на анонимный объект, а затем Select просто Groups:

var resultObjectList = AllGroups.
                       Select(g => new
                               {
                                   GroupItem = g,
                                   UserItems = g.Users.Where(u => !u.IsInactive)
                               }).ToList();

FilteredGroups = resultObjectList.Select(i => i.GroupItem).ToList();

Это не документальная функция и связана с тем, как EF создает SQL-запросы - в этом случае он должен отфильтровывать дочернюю коллекцию, поэтому ваш список FilteredGroups будет содержать только активных пользователей.

Если это работает, вы можете попробовать слить код:

FilteredGroups = AllGroups.
                 Select(g => new
                               {
                                   GroupItem = g,
                                   UserItems = g.Users.Where(u => !u.IsInactive)
                               }).
                 Select(r => r.GroupItem).
                 ToList();

(Это не проверено, и результат зависит от того, как EF будет обрабатывать второй Select, поэтому было бы неплохо, если бы вы сообщили нам, какой метод работает после того, как вы его пробовали).

Ответ 3

попробуйте что-то вроде этого, и у вас все равно будут свои сущности:

FilteredGroups = AllGroups.Select(g => new
{
    Group = g,
    Users = g.Users.Where(u => u.IsInactive == false)
}).AsEnumerable().Select(i => i.Group);

Таким образом, вы все равно сможете использовать Group.Users

Ответ 4

Если вы хотите сохранить структуру сущности, попробуйте следующее:

var userGroups = context.Users.Where(u => !u.IsInactive).GroupBy(u => u.Group);

foreach (var userGroup in userGroups)
{
    // Do group stuff, e.g.:
    foreach (var user in userGroup)
    {
    }
}

И вы, безусловно, можете изменить свои сущности!

Ответ 5

Использовать внутренний запрос linq

var FilteredGroups = (from g in AllGroups
                      select new Group()
                        {
                            ID = g.ID,
                            Name = g.Name,
                            ...
                            Users = (from user in g.Users
                                     where user.IsInactive == false
                                     select user).ToList()
                        });