2010-01-18 12 views
6

Ho un metodo ("GetDataReader", chiamiamolo) che restituisce un SqlDataReader. È all'interno di una classe Singleton DataFactory che mantiene una connessione persistente al database.Come posso "staccare" SqlDataReader dal suo oggetto SqlConnection?

Il problema con questo è che dopo essere stato restituito, DataReader è ancora "connesso" all'oggetto Connection nel mio DataFactory. Così, ho per assicurarsi che il codice che chiama GetDataReader quindi chiama Close() sul DataReader che ritorna, altrimenti, si "aggancia" la connessione con questo:

C'è già un DataReader aperto associato con questo Comando che deve essere chiuso per primo.

Come posso "staccare" il DataReader prima di inviarlo indietro da GetDataReader? O quello, o clonarlo e rimandare il clone? Non voglio dover rendere il codice chiamante sempre esplicitamente chiuso.

Ci deve essere una buona pratica qui.

Aggiornamento:

Grazie a tutti per il vostro contributo. La linea di fondo è che ho bisogno di perdere l'abitudine di usare DataReader e passare a DataTable. Sono molto più gestibili.

Inoltre, grazie per la nota sul pool di connessioni. Lo sapevo, ma non ho messo insieme due e due e mi sono reso conto che stavo reinventando la ruota.

+0

ho avuto * * di smettere di usare DataReaders ... – Deane

risposta

6

DataReader del devono rimanere collegato al db fino a quando non si ha più bisogno di loro - questa è la natura di utilizzare un DataReader quindi non è possibile "staccare" come tali. Quando hai finito con un lettore di dati, devi chiuderlo (.Close()) ma non puoi più utilizzarlo.

Da .NET 2.0, se si utilizza SQL 2005 o versione successiva, è possibile utilizzare MARS (Set di risultati attivi multipli) come spiegato here. Ciò consente di utilizzare una singola connessione per più lettori di dati e comporta solo una modifica della stringa di connessione. Tuttavia, SqlDataReaders non è l'ideale per passare il codice nel modo in cui sembra come si desidera.

In alternativa (che è ciò che penso che devi fare), potresti voler utilizzare un set di risultati disconnessi che è il punto in cui DataSet/DataTables entrano. Si usa un SqlDataAdapter per riempire un DataSet/DataTable con tutti i risultati di un query. È quindi possibile utilizzare la connessione per qualsiasi altro scopo o chiudere la connessione e non influisce sul set di risultati in memoria. È possibile passare il set di risultati attorno al codice senza la necessità di mantenere una connessione di database aperta.

+0

Sì, DataTable sono una migliore approccio qui. Devo smettere di usare DataReader. Ho incontrato questo problema prima - spero, questa volta imparerò la mia lezione. Grazie. – Deane

2

Non persistere la connessione al database. Esiste una funzionalità chiamata "connection pooling". Ottenere una nuova connessione non è costoso.

1

In genere, si consiglia di utilizzare il pool di connessioni anziché una connessione permanente per consentire l'accesso simultaneo da parte di più utenti. L'unico modo in cui posso pensare di fare quello che vuoi fare è caricare un DataSet dal lettore e restituirlo.

0

Penso che potresti ottenere i tuoi set di dati (dati incorporati non connessi) e datareader (nessun dato) confusi. Un DataReader senza SqlCnnection è ... ummm ... solo un Reader, cioè nessun dato ;-)

Penso che il tuo problema sia più in alto nella tua linea di pensiero. Immagino che tu sia un programmatore di vecchia scuola abituato a fare tutto a mano. Nel mondo "gestito" di dot net, molte cose sono gestite per te; ADO.NET dispone già di un efficace sistema di pool di connessioni dati, non è necessario mantenere il proprio pool.

-Oisin

0

Ecco un metodo di supporto a portata di mano per eseguire alcuni SQL contro una connessione, e lo hanno disconnesso dal server:

public static DbDataReader ExecuteReaderClient(DbConnection connection, DbTransaction transaction, String commandText) 
{ 
    DbCommand command = connection.CreateCommand(); 
    command.CommandText = commandText; 
    if (transaction != null) 
     command.Transaction = transaction; 

    DbDataAdapter adapter = DbProviderFactories.GetFactory(connection).CreateDataAdapter(); 

    adapter.SelectCommand = command; 
    DataSet dataset = new DataSet(); 

    try 
    { 
     adapter.Fill(dataset); 
    } 
    catch (Exception e) 
    { 
     throw new Exception(
        e.Message + "\r\n" + 
        "Command Text" + "\r\n" + 
        commandText, e); 
    } 

    try 
    { 
     return dataset.CreateDataReader(); 
    } 
    finally 
    { 
     dataset.Dispose(); 
    } 
} 
Problemi correlati