Linq to Entities, возвращающий все внешние объекты и один или ни одного связанного объекта

Я использую LinqPad с моделью Entity Framework 4 и базой данных MS SQL 2008.

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

Следующий linq создает ассоциацию ObjectQuery<Customer> с Purchases для EntityCollection<Purchase>.

from c in Customers.Include("Purchases")
select c

Теперь я хочу получить всех клиентов только с самой последней покупкой. Если нет покупки, я хочу, чтобы коллекция Purchases была пустой.

Мне нужно что-то вроде следующего, но это поддерживает сущность и ассоциацию. Я хочу получить всех клиентов с коллекцией, ограниченной 0 или 1 покупками.

from c in Customers
from p in c.Purchases.Where(p => p.PurchaseDate == c.Purchases.Max(m => m.PurchaseDate).DefaultIfEmpty()
select new { CustomerID = c.CustomerID, PurchaseID = (int?)p.PurchaseID }

В моей службе я возвращаю List<Customer>, поэтому я думаю, что мне нужно поддерживать сущность Customer и ассоциацию Purchases в возврате запроса linq.

Вариант использования:

var customers = CustomerService.GetCustomersAndMostRecentOrder();
foreach (Customer c in customers) {
    Console.WriteLine(c.Lastname + ":" + 
                     c.Purchases.Count() == 0 ? "None" : c.Purchases[0].PurchaseOrder);
}

Спасибо за ваше понимание.


person GoClimbColorado    schedule 22.06.2011    source источник


Ответы (1)


Вам нужно будет выполнить часть запроса с помощью linq-to-entities, а затем оставшуюся часть с linq-to-objects, например:

var query = (from c in Customers
             select new 
             { 
               Customer = c, 
               Purchase = c.Purchases.OrderByDescending(p => p.PurchaseDate).FirstOrDefault()
             })
            .AsEnumerable()
            .Select(c => new Customer()
                         {
                           CustomerID = c.CustomerID,
                           CustomerProperty2 = c.CustomerProperty2,
                           CustomerProperty3 = c.CustomerProperty3,
                           ...,
                           Purchases = new Purchase[] { c.Purchase }
                         } 
                    );
person Aducci    schedule 22.06.2011
comment
Я пробовал это, но на выходе получаю 0 покупок. -- Добавлено as EntityCollection<Purchase> на Purchases = c.Purchases - person GoClimbColorado; 22.06.2011
comment
Попробуйте изменить Take(1) на FirstOrDefault() - person Aducci; 22.06.2011
comment
Нет, это меняет его обратно на экземпляр Purchase, а не на набор Purchases. Также попробовал DefaultIfEmpty()... получить 0 покупок. - person GoClimbColorado; 22.06.2011
comment
Посмотрите на полный ответ, с linq-to-objects в последней строке есть: Purchases = new Purchase[] { c.Purchase} - person Aducci; 22.06.2011
comment
Невозможно неявно преобразовать тип ...Purchase[] в ...EntityCollection<Purchase> Извините, я знаю, что вы правы, я просто продолжаю бороться с синтаксисом, что, вероятно, означает, что я делаю что-то не так. - person GoClimbColorado; 23.06.2011