В ответе Джона, который работает просто отлично, IQueryable, однако, будет преобразован в IEnumerable, поскольку вы вызываете ToList () для него. Это приведет к выполнению запроса и получению ответа. Для вашей ситуации это может быть нормально, так как вы хотите получить товары для корзины, а количество товаров, вероятно, будет значительно меньше.
Однако я сталкиваюсь с аналогичной ситуацией, когда хочу найти друзей для члена. Дружба зависит от того, к какой группе принадлежат два члена - если они разделяют хотя бы одну группу, они друзья. Таким образом, мне нужно получить все членство для всех групп для определенного участника, а затем извлечь всех участников из этих групп.
Подход ToList не будет применим в моем случае, так как он будет выполнять запрос каждый раз, когда я хочу обрабатывать своих друзей различными способами, например найти материал, которым мы можем поделиться. Извлечение всех членов из базы данных вместо того, чтобы просто работать над запросом и выполнить его в самый последний момент, снизит производительность.
Тем не менее, моя первая попытка в этой ситуации состояла в том, чтобы сделать именно это - извлечь все группы, к которым я принадлежал (IQueryable), инициировать результат List (IEnumerable), затем выполнить цикл по всем группам и добавить всех участников к результату, если они были нет уже в списке. Наконец, поскольку мой интерфейс принудительно возвращал IQueryable, я возвратил список с помощью AsIQueryable.
Это был неприятный кусок кода, но по крайней мере он работал. Выглядело это примерно так:
var result = new List<Member>();
foreach (var group in GetGroupsForMember(member))
result.AddRange(group.GroupMembers.Where(x => x.MemberId != member.Id && !result.Contains(x.Member)).Select(groupMember => groupMember.Member));
return result.AsQueryable();
Тем не менее, это ПЛОХО, поскольку я добавляю ВСЕ общие участники в список, а затем преобразую список в IQueryable только для удовлетворения моего условия публикации. Я буду извлекать всех участников, которые затронуты из базы данных, каждый раз, когда я хочу что-то с ними сделать.
Представьте себе разбитый на страницы список - тогда я бы просто хотел выбрать определенный диапазон из этого списка. Если это делается с помощью IQueryable, запрос просто завершается оператором разбиения на страницы. Если это сделано с помощью IEnumerable, запрос уже выполнен, и все операции применяются к результату в памяти.
(Как вы также можете заметить, я также перемещаюсь вниз по отношениям сущности (GroupMember => Member), что увеличивает связь, может в дальнейшем вызывать всевозможные неприятные ситуации. Я также хотел удалить это поведение).
Итак, сегодня вечером я взял еще один раунд и закончил с гораздо более простым подходом, где я выбираю такие данные:
var groups = GetGroupsForMember(member);
var groupMembers = GetGroupMembersForGroups(groups);
var memberIds = groupMembers.Select(x => x.MemberId);
var members = memberService.GetMembers(memberIds);
Два метода Get поддерживают IQueryable и никогда не преобразуют его в список или любой другой IEnumerable. Третья строка просто выполняет LINQ-запрос поверх IEnumerable. Последняя строка просто берет идентификаторы участников и извлекает всех участников из другой службы, которая также работает исключительно с IQueryables.
Это, вероятно, все еще ужасно с точки зрения производительности, но я могу оптимизировать его позже, если потребуется. По крайней мере, я избегаю загрузки ненужных данных.
Дайте мне знать, если я здесь ужасно неправ.