2010-07-18 16 views
14

Quindi sto cercando di capire IQueryable<T>. Un tutorial che sto leggendo suggerisce di usarlo ma non è proprio sicuro del perché. Il codice restituisce semplicemente alcuni valori usando LINQ to SQL. L'ho già fatto molte volte in passato, ma non utilizzando IQueryable<T>Ho problemi a capire IQueryable <T>

Perché utilizzarlo con le mie funzioni che restituiscono più di 1 valore?

Ecco il mio codice:

public IQueryable<Items> GetItems() 
    { 
     return from item in db.Items 
       where item.IsActive == true 
       orderby item.ItemNumber 
       select item; 
    } 
+2

ottima domanda. mi hai risparmiato ore di ricerca. – KyleM

risposta

12

IQueryable rappresenta la query come un albero di espressione senza valutare sul server. Ciò consente di specificare ulteriori elaborazioni prima di generare effettivamente SQL.

Nel caso di cui sopra, questo significa che è possibile fare cose con il risultato della chiamata GetItems(), e hanno la query originale e il materiale extra inviato come una singola query:

var recentItems = from item in GetItems() 
        where item.Timestamp > somedate 
        select item; 

foreach (var item in recentItems) 
{ 
    // Do something with an active recent item. 
} 

Nulla viene inviato al server finché non proviamo a consumare il risultato nel ciclo foreach. A quel punto, il provider LINQ-to-SQL valuta l'intera espressione, compresi i bit generati all'interno di GetItems() e i bit specificati dopo, ed emette una singola istruzione SQL che seleziona tutti gli elementi sia attivi che recenti.

Per chiarire un aspetto tecnico, lo IQueryable<T> è un IEnumerable<T> e il suo provider calcola l'SQL finale quando si tenta di richiamare il metodo GetEnumerator() su di esso. Puoi farlo esplicitamente chiamandolo o implicitamente utilizzandolo in un'istruzione foreach. Inoltre, i metodi di estensione come ToArray() eseguiranno uno di questi internamente, producendo così lo stesso effetto.

+0

Quindi IEnumerable <> - viene valutato solo 'foreach' o' .ToArray() 'viene chiamato. Quindi, perché IQueryable <> è diverso da IEnumerable <>? – Enigmativity

+0

Un IQueryable * è * un oggetto IEnumerable ed entrambi possono fornire una raccolta tardiva. Ma il punto di IQuerable in L2S è l'esecuzione ritardata di SQL. Con IQueryable, puoi continuare ad aggiungere elementi di query, come le condizioni .Where() fino al momento in cui finalmente inizi a enumerare. A quel punto, IQueryable esegue infine la query SQL e riempie una raccolta per consentirne l'enumerazione. Se sei sicuro di aver terminato la tua query e nulla che chiami il tuo metodo debba aggiungervi più condizioni, allora puoi decidere di chiamare semplicemente .ToList() ed essere fatto senza restituire un IQuerable. – mattmc3

+0

'IQueryable ' implementa l'interfaccia 'IEnumerable ', quindi un 'IQueryable' può essere usato come' IEnumerable'. La grande differenza è che IQueryable è una definizione di un'operazione piuttosto che l'operazione (codice compilato) stessa. Ciò consente al provider LINQ di SQL di analizzare questo e convertirlo in SQL. Questo sarebbe (quasi) impossibile da fare con il normale codice compilato. – Steven

5

Un IQueryable (prima che sia enumerato) non è i risultati stessi ma la logica utilizzata per restituire tali risultati.

Per utilizzare un esempio LINQ2SQL ... immagina di restituire un IQueryable di client. Sotto il cofano che non sarà una lista di clienti (fino a quando non ToList()), ma sarà actualy una query SQL in questo modo:

SELECT * FROM [Clients] 

Ora, questo è a portata di mano perché non abbiamo colpito la base di dati ancora! Allora supponiamo quando quel IQueriable torna vogliamo perfezionare il basso per i clienti chiamato "Bob" che possiamo fare:

var clients = GetClients().Where(c => c.Name == "Bob"); 

Ora l'IQueriable assomiglia a questo sotto il cofano:

SELECT * FROM [Clients] WHERE Name = 'Bob'. 

Ora, quando Io faccio clients.ToList(), quella query verrà eseguita, il database verrà colpito e io ho un elenco di client chiamato bob senza dover selezionare tutti i client quindi scorrere attraverso di essi in memoria, o eseguire 2 hit di database separati.

Per un esempio di questo ti morde nel dietro prova e ottenere elementi figlio quando il tuo datacontext ha abbandonato l'ambito (ad esempio: eseguire la selezione all'interno di un'istruzione using). È qui che le opzioni di caricamento sono utili, in LINQ2SQL.

Speranza che aiuti

+0

Così è IEnumerable <> - viene valutato solo '.ToList()' viene chiamato. Quindi, perché IQueryable <> è diverso da IEnumerable <>? – Enigmativity

+0

I tuoi dati sono ancora un albero di espressioni prima che l'IQueryable sia enumerato ... Nell'esempio di LINQ2SQL non puoi avere SELECT * FROM Client come IEnumerable poiché è un'espressione e non contiene valori enumerabili finché non viene eseguita la query self. Mentre rimane un IQueryable non numerato, è possibile aggiungere clausole che aumentano l'albero delle espressioni. – jdoig

Problemi correlati