2010-01-18 15 views
6

Tengo un método ("GetDataReader", vamos a llamarlo) que devuelve un SqlDataReader. Está dentro de una clase Singleton DataFactory que mantiene una conexión persistente con la base de datos.¿Cómo puedo "separar" un SqlDataReader de su objeto SqlConnection?

El problema con esto es que después de ser devuelto, el DataReader todavía está "conectado" al objeto Connection en mi DataFactory. Por lo tanto, tengo que asegurarse de que el código que llama GetDataReader continuación, llama a Close() en el DataReader que regresa, si no, "bloquea" la conexión con esto:

ya hay un DataReader abierto asociado con este Comando que debe cerrarse primero.

¿Cómo puedo "separar" el DataReader antes de volver a enviarlo desde GetDataReader? ¿O eso, o clonarlo y devolver el clon? No quiero tener que hacer que el código de llamada siempre lo cierre de manera explícita.

Tiene que haber una mejor práctica aquí.

Actualización:

Gracias a todos por sus comentarios. La conclusión es que necesito perder el hábito de usar DataReaders y cambiar a DataTables. Son mucho más manejables.

Además, gracias por la nota sobre la agrupación de conexiones. Lo sabía, pero no me puse dos ni dos y me di cuenta de que estaba reinventando la rueda.

+0

I * tengo * dejar de usar DataReaders ... – Deane

Respuesta

6

de DataReader deben estar conectados a la base de datos hasta que ya no los necesita - que es la naturaleza de la utilización de un DataReader por lo que no se puede "desconectar" como tales. Cuando haya terminado con un lector de datos, debe cerrarlo (.Close()) pero ya no podrá usarlo.

Desde .NET 2.0 en adelante, si está utilizando SQL 2005 o posterior, puede hacer uso de MARS (Conjuntos de resultados activos múltiples) como se explica here. Esto le permite usar una única conexión para múltiples lectores de datos y solo implica un cambio en su cadena de conexión. Sin embargo, SqlDataReaders no son ideales para pasar su código de la manera que parece.

Alternativamente (que es lo que creo que necesita hacer), es posible que desee utilizar un conjunto de resultados desconectado que es donde DataSet/DataTables entran. Utiliza un SqlDataAdapter para llenar un DataSet/DataTable con todos los resultados de un consulta. Luego puede usar la conexión para cualquier otro propósito, o cerrar la conexión, y no afecta su resultado en memoria. Puede pasar su conjunto de resultados alrededor de su código sin necesidad de mantener una conexión de base de datos abierta.

+0

Sí, tablas de datos son una mejor acercarse aquí. Debo dejar de usar DataReaders. Me he encontrado con este problema antes - con suerte, aprenderé mi lección esta vez. Gracias. – Deane

2

No persista la conexión de la base de datos. Hay una función llamada "agrupación de conexiones". Obtener una nueva conexión no es costoso.

1

En general, la mejor práctica sería utilizar la agrupación de conexiones en lugar de una conexión persistente, para permitir el acceso simultáneo de varios usuarios. La única forma en que puedo pensar para hacer lo que quieres hacer es cargar un DataSet del lector y devolverlo.

0

Creo que podría estar confundiendo los conjuntos de datos (datos incrustados incrustados) y los lectores de datos (sin datos). Un DataReader sin una SqlCnnection es ... ummm ... solo un Reader, es decir, sin datos ;-)

Creo que su problema está más arriba en su línea de pensamiento. Supongo que eres un programador de la vieja escuela acostumbrado a hacer todo a mano. En el mundo "administrado" de dot net, se gestionan muchas cosas para ti; ADO.NET ya tiene un sistema efectivo de agrupación de conexiones de datos, no debería necesitar mantener su propio grupo.

-Oisin

0

Aquí es un método de ayuda práctica para ejecutar algún SQL en una conexión, y lo han desconectado del servidor:

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(); 
    } 
} 
Cuestiones relacionadas