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)
});
Благодарю вас за помощь!
Ответы
Ответ 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()
});