2012-12-05 8 views
7

Piszę zapytanie z SelectMany i sprawdzam SQL, które generuje w LINQPad. Zapytanie jest bardzo proste.SelectMany tworzy wiele instrukcji SQL Select zamiast jednego z łączeniem

Załóżmy, że mam 3 podmioty: Customer, Order, OrderItem. OrderItem przechowuje informacje o zamówionym produkcie iw jakiej ilości.

Chcę uzyskać wszystkie OrderItems dla jednego klienta.

context.Customers.First().Orders.SelectMany(o=>o.OrderItems) 

Otrzymuję zestaw wyników zgodnie z oczekiwaniami, ale SQL jest dla mnie naprawdę dziwny. Jest kilka zdań wybranych. Najpierw wybiera jednego klienta, co jest w porządku. Następnie wybiera jedno Zamówienie (ponieważ ten klient ma tylko jedno), a następnie tworzy jeden wybór dla każdego OrderItem w poprzednio wybranym Order ... Tak więc otrzymuję tyle zaznaczeń, ile jest OrderItems + Orders dla wybranych Customer. Tak to wygląda:

select top 1 from Customers; 

select * from Orders where CustomerID = @cID; 

select * from OrderItems where OrderID = @o1; 
select * from OrderItems where OrderID = @o2; 
select * from OrderItems where OrderID = @o3; 
select * from OrderItems where OrderID = @o4; 

co by się spodziewać jest coś takiego:

select oi.* 
from OrderItems oi 
join Orders o on o.OrderID = oi.OrderId 
join Customers c on c.CustomerID = o.CustomerID 
where c.CustomerID = @someID 

Jeden select, ładne i czyste.

Czy naprawdę działa tak, czy robię coś źle, a może coś jest nie tak z moim modelem? Nie mogę znaleźć nigdzie przykładów tego, jak tego rodzaju prosty kod powinien być przetłumaczony na SQL.

To nie ma znaczenia dla małych ilościach, ale gdy klient musiałby 100 zleceń z 200 pozycji porządkowych każdy, to nie byłoby 20 000 wybiera ...

Odpowiedz

8

Należy używać następujących dla zapytania (kwerendy dla elementów zlecenie konkretnego klienta z someId):

context.Customers.Where(c => c.Id == someId) 
    .SelectMany(c => c.Orders.SelectMany(o => o.OrderItems)) 

lub - aby odtworzyć zachowanie First() ale za pomocą pojedynczego zapytania DB:

context.Customers.Take(1) 
    .SelectMany(c => c.Orders.SelectMany(o => o.OrderItems)) 

Jesteś oryginalna kwerenda ładuje klientowi First (zapytanie 1), a następnie leniwe załadunku ładuje Orders zbiór tego klienta (zapytanie 2), a następnie lazy loading ponownie ładuje kolekcja przedmiotów order za każdy załadowany Order (zapytanie 3 do n). Aby uniknąć tych wszystkich wielokrotnych zapytań, nie wolno używać "metody wykonywania zapytań", takiej jak First() lub ToList() itp. Wewnątrz wyrażenia zapytania.

+0

Ach, to jest chwytliwe. Wypróbowałem to i teraz działa. Dzięki! – Episodex

Powiązane problemy