как добавить IQueryable в цикле - PullRequest
2 голосов
/ 08 ноября 2011

У меня есть простой цикл foreach, который просматривает идентификаторы продуктов, которые я сохранил в корзине пользователя, и просматривает сведения о продукте из базы данных.

Как видно из моего кода, то, что у меня есть в настоящее времявернет самый последний элемент на экране - поскольку переменная перезаписывается в цикле.Я хотел бы иметь возможность констатировать это так, чтобы я мог отображать сведения о продукте только для товаров в корзине.

Я знаю, что мог бы сделать что-то очень простое, например, хранить только идентификаторы продукта в ретрансляторе, который я использую, иonitemdatabound вызывает базу данных, но я хотел бы сделать только один вызов базы данных, если это возможно.

В настоящее время у меня есть следующее (в примере удалены сложные объединения, но если это имеет значение, дайте мне знать):

IQueryable productsInBasket = null;
    foreach (var thisproduct in store.BasketItems)
    {
        productsInBasket = (from p in db.Products
                                 where p.Active == true && p.ProductID == thisproduct.ProductID
                                 select new
                                 {
                                     p.ProductID,
                                     p.ProductName,
                                     p.BriefDescription,
                                     p.Details,
                                     p.ProductCode,
                                     p.Barcode,
                                     p.Price
                                 });
    }

    BasketItems.DataSource = productsInBasket;
    BasketItems.DataBind();

Спасибо за помощь!

Ответы [ 2 ]

7 голосов
/ 08 ноября 2011

Звучит так, как будто вы действительно хотите что-то вроде:

var productIds = store.BasketItems.Select(x => x.ProductID).ToList();
var query = from p in db.Products
            where p.Active && productIds.Contains(p.ProductID)
            select new
            {
                p.ProductID,
                p.ProductName,
                p.BriefDescription,
                p.Details,
                p.ProductCode,
                p.Barcode,
                p.Price
            };
0 голосов
/ 20 ноября 2011

В ответе Джона, который работает просто отлично, 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.

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

Дайте мне знать, если я здесь ужасно неправ.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...