2012-12-05 10 views
7

Sto scrivendo una query con SelectMany e ho controllato SQL generato in LINQPad. La query è molto semplice.SelectMany crea molte istruzioni di selezione SQL invece di una con join

Diciamo che ho 3 entità: Customer, Order, OrderItem. OrderItem contiene informazioni su quale prodotto è ordinato e in quale quantità.

Voglio ottenere tutto il OrderItems per un cliente.

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

vengo set di risultati come mi aspetto, ma SQL è davvero strano per me. Ci sono un sacco di dichiarazioni selezionate. Prima seleziona un cliente, che è ok. Quindi seleziona un ordine (poiché questo cliente ne ha solo uno), quindi crea una selezione per ogni OrderItem in Order precedentemente selezionato ... Quindi ottengo altrettanti selezioni quanti sono OrderItems + Orders per il Customer selezionato. Quindi sembra che:

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; 

quello che mi aspetterei è qualcosa di simile:

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 

Uno di selezione, bella e pulita.

SelectMany funziona davvero così o sto facendo qualcosa di sbagliato, o forse qualcosa di sbagliato è con il mio modello? Non riesco a trovare nessun esempio su come quel tipo di semplice SelectMany dovrebbe tradurre in SQL.

Questo non ha importanza per i piccoli numeri, ma quando un cliente dovrebbe avere 100 ordini con 200 articoli dell'ordine ciascuno, allora non ci sarebbe 20 000 seleziona ...

risposta

8

Si consiglia di utilizzare il seguente per la query (per interrogare per gli articoli di ordine di un cliente specifico con someId):

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

o - per riprodurre il comportamento di First() ma con una singola query DB:

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

Si query originale carica il cliente con First (query 1), quindi lazy loading carichi la raccolta Orders di tale cliente (query 2), quindi lazy loading nuovamente carichi raccolta voci dell'ordine per ciascun caricato Order (query 3 tonnellata). Per evitare tutte quelle query multiple non devi utilizzare un "metodo di esecuzione della query" come First() o ToList(), ecc. All'interno dell'espressione della query.

+0

Aah, questo è orecchiabile. L'ho provato e ora funziona. Grazie! – Episodex

Problemi correlati