Resa i record del database di restituzione utilizzando LinqToSql?

Ho un metodo di fornitura in DAL:

public IEnumerable GetRecords() { using (LinqDataContext context = new LinqDataContext()) { var records = context.RecordTable; foreach (RecordType record in records) { yield return record; } } } 

Il metodo consumer utilizza i record in un ciclo foreach . In questo modo voglio salvare un utilizzo della memoria non memorizzando nella cache tutti i record di RecordTable , poiché LinqToSql utilizza un DataReader dietro la scena.

Ho due domande su questo scenario però:

  1. È vero che yield-return above salva le risorse e lavora più velocemente rispetto al caching di tutti i record su un array (.ToArray ())?

  2. La connessione dati verrà automaticamente chiusa correttamente (intendo l’istruzione using ) se si verificherà un errore all’interno del ciclo foreach del metodo di consumo O se il metodo di consumo interromperà il ciclo foreach nel mezzo (come trovato un record e break ) ?

Nel caso dell’esecuzione di una query di base, può funzionare in questo modo (certamente è ansible) – tuttavia, nel caso di interrogare una Table nuda Table , potrebbe essere che tutto fa da primo buffer; potresti forse provare a interrogare il conteggio durante l’iterazione o eseguire una traccia. In questo caso, ho il sospetto che si tamponerà per primo.

Chiuso: dipende anche da: p Se qualcuno sta usando foreach , allora sì: poiché foreach esplicitamente l’iteratore per finally . Però! Non è garantito se qualcuno lo fa, ad esempio (molto cattivo e negligente):

 var iter = yourData.GetEnumerator(); if(iter.MoveNext()) { Console.WriteLine(iter.Current.Name); // first record of, say, 20 } // and don't dispose the iterator == bad 

quindi poiché l’iteratore non ha a: get disposed, b: exhaust stesso, e c: non si blocca, non si spegne correttamente (nessuna di queste 3 condizioni lo chiuderà correttamente). Enfasi: questo è un caso patologico: normalmente è ragionevolmente sicuro dire “si chiuderà, sì”.

Se vuoi garantire il non buffering, nota che “dapper” lo ha, se hai impostato il buffered su false :

 IEnumerable customers = connection.Query( "select * from Customer", buffered: false); 

(può anche gestire i parametri, ecc.)

1) il yield non sarà necessariamente più veloce per ottenere tutti i valori, ma consentirebbe al codice di iniziare a gestire i risultati prima che il database abbia restituito tutti i risultati. Ovvero, yield restituisce il primo risultato nell’istante in cui viene visualizzato, mentre ToArray () deve attendere la visualizzazione di tutti i risultati prima di tornare. Naturalmente, se i provider sottostanti restituiscono tutti i risultati contemporaneamente a causa del buffering o di altri motivi, ciò potrebbe non fare la differenza.

2) Sì, l’ using eliminerà LinqDataContext indipendentemente dal modo in cui si esce dal blocco using (eccezioni / return / break / …)

  1. L’iteratore verrà valutato pigramente. Tirerà il primo object e poi lo “renderà” al suo consumatore. L’impatto sulle prestazioni dipenderà dal modo in cui viene implementato LinqDataContext (potrebbe memorizzare la cache internamente). L’utilizzo di ToArray () o ToList () imporrà tutti gli elementi fuori da LinqDataContext prima di procedere. Pertanto, l’utilizzo di ToArray () non produrrà nulla finché LinqDataContext non restituirà ogni elemento. Che sia ottimale o no, dipende da te.
  2. Sì, il “usando” verrà applicato correttamente.