2012-01-31 10 views
7

È sopra una cattiva idea, sarà prima selezionare tutte le righe del database e poi trovare quello o sarà intelligente e vedere il contesto è utilizzato all'interno e solo recuperare l'una riga.Linq, è select(). SingleorDefault() una cattiva idea?

Motivo per cui è necessario restituire solo il Guid e il risultato.

return Newtonsoft.Json.JsonConvert.SerializeObject(queueitem, Formatting.Indented); 

come faccio a trovare la risposta a questo senza dover per monitorare il flusso di rete o le richieste effettuate al database?

risposta

13

"sarà in primo luogo selezionare tutte le righe del database e quindi trovare quello"

Tecnicamente, no, la combinazione di .Selezionare seguita da .SingleOrDefault volontà non farlo. Select() imposta i parametri per la query, ma in realtà non recupera alcun dato. L'esecuzione posticipata di LINQ non recupera alcuna riga finché qualcosa non deve effettivamente produrre un risultato di dati. È possibile comporre più query insieme (.Seleziona (...). Selezionare (..) ecc. E niente recupera effettivamente alcuna riga finché non si esegue un'operazione che restituisce dati, come Primo() o. Lista().

Tuttavia, l'uso di Single() può comportare la scansione dell'intero set di dati per dimostrare che l'unica riga corrispondente è la riga corrispondente.

Pensateci: come farà la query sa che quella riga è l'unica riga nel set di dati che corrisponde? Dovrà cercare di trovare la riga successiva. Se c'è davvero solo una riga che corrisponde a milioni nel set di dati, Single() potrebbe dover scorrere tutti quei milioni di righe per dimostrare che la corrispondenza corrente è l'unica e unica corrispondenza.

Se il set di dati è SQL ei dati sono indicizzati in modo da consentire l'ottimizzazione delle query, Single() potrebbe non essere così male. Ma se i tuoi dati SQL non sono indicizzati in modo utile a questa query, Single() potrebbe creare molto lavoro per il server SQL.

Single() è appropriato se la logica del programma ha realmente bisogno di sapere che la riga restituita è l'unica riga dell'intero set di dati. Tuttavia, ci sono altri modi per garantire unicità. Se puoi impostare una chiave primaria sui tuoi dati che corrisponde alla tua condizione LINQ, solo una riga corrispondente può esistere/essere aggiunta al database per cominciare, quindi non hai davvero bisogno di Single(). (E ironicamente, anche le prestazioni di Single() saranno banali in questo caso perché l'indice della chiave primaria può essere utilizzato per ottimizzare la query)

Se si desidera solo la prima riga che corrisponde alla condizione, utilizzare Primo () invece di Single(). First() deve solo analizzare le righe di dati fino a quando non trova la prima corrispondenza. Non è necessario continuare la scansione delle righe per dimostrare che la prima corrispondenza è l'unica corrispondenza, come Single().

+0

Grazie. Ho usato firstordefault ma quando ho fatto la domanda in qualche modo ho dimenticato. –

+0

Stavo per suggerire anche FirstOrDefault(). –

1

L'effettiva query eseguita dipende in realtà dal provider Linq, ma sì, il provider Linq non valuterà fino all'ultimo momento, in modo da conoscere il contesto (SingleOrDefault) prima dell'esecuzione della query. Una brava persona non recupera nulla non necessariamente.

Una buona implementazione di Linq preleverà effettivamente 2 righe, poiché SingleOrDefault si occupa di 3 casi;

  • Nessuna riga restituita -> ritorna di default
  • Una fila restituita -> Restituisce quella riga
  • più di una riga restituita -> eccezione del tiro (sequenza contiene più di un elemento)
2

SingleOrDefault - Restituisce l'unico elemento di una sequenza, o un valore predefinito se la sequenza è vuota; questo metodo genera un'eccezione se c'è più di un elemento nella sequenza.

FirstOrDefault - Restituisce il primo elemento di una sequenza o un valore predefinito se la sequenza non contiene elementi.

Semanticamente, si desidera FirstorDefault poiché la domanda indica più righe restituite.

+1

Sei corretto. Ma non era la domanda posta. –

3

Sono sicuro che questo non restituirà l'intero database prima del filtro poiché l'esecuzione della query non si verifica fino a quando non viene eseguita l'istruzione di 'valutazione', che è il SingleOrDefault() in questa query.

Se trovassi

context.CrawlerQueues.ToList().Select(cq => new{cq.Guid,cq.Result}).SingleOrDefault(cq => cq.Guid == guid);

quindi questo dovrebbe valutare il ToList() prima del filtraggio, ma la query così com'è va bene.

Se non si è sicuri del percorso di valutazione o dell'SQL generato dalle istruzioni LINQ, LINQPad è uno strumento molto utile che semplifica notevolmente il lavoro con Linq, Linq2Sql, EF.

Problemi correlati