Récupération de données en utilisant un DataReader

Pour récupérer des données en utilisant un DataReader, créez une instance de l’objet Command, puis créez un DataReader en appelant Command.ExecuteReader pour extraire des lignes d’une source de données. Le DataReader fournit un flux de données sans mise en mémoire tampon qui permet à la logique procédurale de traiter efficacement les résultats provenant d’une source de données de façon séquentielle. Le DataReader se révèle être un bon choix quand vous récupérez de grandes quantités de données, car celles-ci ne sont pas mises en cache dans la mémoire.

Voici un exemple d’utilisation d’un DataReaderreader représente un DataReader valide et où command représente un objet Command valide.

reader = command.ExecuteReader();  
reader = command.ExecuteReader()

Utilisez la méthode DataReader.Read pour obtenir une ligne des résultats de la requête. Vous pouvez accéder à chaque colonne de la ligne retournée en passant le nom ou la référence ordinale de la colonne au DataReader. Cependant, pour permettre de meilleures performances, le DataReader fournit une série de méthodes qui vous permettent d’accéder aux valeurs des colonnes dans leurs types de données natifs (GetDateTime, GetDouble, GetGuid, GetInt32, etc.). Pour obtenir une liste de méthodes d’accesseur typées pour les DataReaders spécifiques au fournisseur de données, consultez OleDbDataReader et SqlDataReader. L’utilisation des méthodes d’accesseur typées quand vous connaissez le type de données sous-jacent réduit la quantité des conversions de type nécessaires lors de l’extraction de la valeur de colonne.

L’exemple de code suivant boucle dans un objet DataReader et retourne deux colonnes à partir de chaque ligne.

static void HasRows(SqlConnection connection)
{
    using (connection)
    {
        SqlCommand command = new(
          "SELECT CategoryID, CategoryName FROM Categories;",
          connection);
        connection.Open();

        SqlDataReader reader = command.ExecuteReader();

        if (reader.HasRows)
        {
            while (reader.Read())
            {
                Console.WriteLine("{0}\t{1}", reader.GetInt32(0),
                    reader.GetString(1));
            }
        }
        else
        {
            Console.WriteLine("No rows found.");
        }
        reader.Close();
    }
}
Private Sub HasRows(ByVal connection As SqlConnection)
    Using connection
        Dim command As SqlCommand = New SqlCommand( _
          "SELECT CategoryID, CategoryName FROM Categories;", _
          connection)
        connection.Open()

        Dim reader As SqlDataReader = command.ExecuteReader()

        If reader.HasRows Then
            Do While reader.Read()
                Console.WriteLine(reader.GetInt32(0) _
                  & vbTab & reader.GetString(1))
            Loop
        Else
            Console.WriteLine("No rows found.")
        End If

        reader.Close()
    End Using
End Sub

Fermeture du DataReader

Appelez toujours la méthode Close quand vous avez fini d’utiliser l’objet DataReader.

Si votre Command contient des paramètres de sortie ou des valeurs de retour, ces valeurs ne sont pas disponibles tant que le DataReader n’est pas fermé.

Pendant qu’un DataReader est ouvert, la Connexion est utilisée exclusivement par ce DataReader. Vous ne pouvez pas exécuter de commandes pour la Connexion, y compris créer un autre DataReader, tant que le DataReader d’origine n’est pas fermé.

Notes

N’appelez pas Close ou Dispose sur une Connexion, sur un DataReader ou sur tout autre objet géré dans la méthode Finalize de votre classe. Dans un finaliseur, libérez seulement les ressources non managées que votre classe possède directement. Si votre classe ne possède pas de ressources non gérées, n’incluez pas de méthode Finalize dans la définition de votre classe. Pour plus d’informations, consultez Nettoyage de la mémoire.

Récupération de plusieurs jeux de résultats en utilisant NextResult

Si le DataReader retourne plusieurs jeux de résultats, appelez la méthode NextResult pour boucler séquentiellement dans les jeux de résultats. L'exemple suivant montre l'objet SqlDataReader traitant les résultats de deux instructions SELECT utilisant la méthode ExecuteReader.

static void RetrieveMultipleResults(SqlConnection connection)
{
    using (connection)
    {
        SqlCommand command = new(
          "SELECT CategoryID, CategoryName FROM dbo.Categories;" +
          "SELECT EmployeeID, LastName FROM dbo.Employees",
          connection);
        connection.Open();

        SqlDataReader reader = command.ExecuteReader();

        while (reader.HasRows)
        {
            Console.WriteLine("\t{0}\t{1}", reader.GetName(0),
                reader.GetName(1));

            while (reader.Read())
            {
                Console.WriteLine("\t{0}\t{1}", reader.GetInt32(0),
                    reader.GetString(1));
            }
            reader.NextResult();
        }
    }
}
Private Sub RetrieveMultipleResults(ByVal connection As SqlConnection)
    Using connection
        Dim command As SqlCommand = New SqlCommand( _
          "SELECT CategoryID, CategoryName FROM Categories;" & _
          "SELECT EmployeeID, LastName FROM Employees", connection)
        connection.Open()

        Dim reader As SqlDataReader = command.ExecuteReader()

        Do While reader.HasRows
            Console.WriteLine(vbTab & reader.GetName(0) _
              & vbTab & reader.GetName(1))

            Do While reader.Read()
                Console.WriteLine(vbTab & reader.GetInt32(0) _
                  & vbTab & reader.GetString(1))
            Loop

            reader.NextResult()
        Loop
    End Using
End Sub

Obtention d’informations de schéma à partir du DataReader

Pendant qu’un DataReader est ouvert, vous pouvez extraire des informations de schéma sur le jeu de résultats actif en utilisant la méthode GetSchemaTable. GetSchemaTable retourne un objet DataTable rempli de lignes et de colonnes qui contiennent les informations de schéma pour le jeu de résultats actif. La DataTable contient une ligne pour chaque colonne du jeu de résultats. Chaque colonne de la table du schéma est mappée à une propriété des colonnes retournées dans les lignes du jeu de résultats, où ColumnName est le nom de la propriété et où la valeur de la colonne est la valeur de la propriété. L’exemple de code suivant écrit les informations de schéma pour DataReader.

static void GetSchemaInfo(SqlConnection connection)
{
    using (connection)
    {
        SqlCommand command = new(
          "SELECT CategoryID, CategoryName FROM Categories;",
          connection);
        connection.Open();

        SqlDataReader reader = command.ExecuteReader();
        DataTable schemaTable = reader.GetSchemaTable();

        foreach (DataRow row in schemaTable.Rows)
        {
            foreach (DataColumn column in schemaTable.Columns)
            {
                Console.WriteLine(string.Format("{0} = {1}",
                   column.ColumnName, row[column]));
            }
        }
    }
}
Private Sub GetSchemaInfo(ByVal connection As SqlConnection)
    Using connection
        Dim command As SqlCommand = New SqlCommand( _
          "SELECT CategoryID, CategoryName FROM Categories;", _
          connection)
        connection.Open()

        Dim reader As SqlDataReader = command.ExecuteReader()
        Dim schemaTable As DataTable = reader.GetSchemaTable()

        Dim row As DataRow
        Dim column As DataColumn

        For Each row In schemaTable.Rows
            For Each column In schemaTable.Columns
                Console.WriteLine(String.Format("{0} = {1}", _
                  column.ColumnName, row(column)))
            Next
            Console.WriteLine()
        Next
        reader.Close()
    End Using
End Sub

Utilisation de chapitres OLE DB

Les jeux de lignes hiérarchiques, ou chapitres, (DBTYPE_HCHAPTER de type OLE DB, adChapter de type ADO) peuvent être récupérés en utilisant le OleDbDataReader. Quand une requête incluant un chapitre est retournée en tant que DataReader, le chapitre est retourné en tant que colonne dans ce DataReader et est exposé en tant qu’objet DataReader.

Le DataSet ADO.NET peut aussi être utilisé pour représenter des jeux de lignes hiérarchiques en utilisant des relations parent-enfant entre les tables. Pour plus d’informations, consultez DataSets, DataTables et DataViews.

L'exemple de code suivant utilise le fournisseur MSDataShape pour générer une colonne chapitre de commandes pour chaque client d'une liste de clients.

Using connection As OleDbConnection = New OleDbConnection(
    "Provider=MSDataShape;Data Provider=SQLOLEDB;" &
    "Data Source=localhost;Integrated Security=SSPI;Initial Catalog=northwind")

    Using custCMD As OleDbCommand = New OleDbCommand(
        "SHAPE {SELECT CustomerID, CompanyName FROM Customers} " &
        "APPEND ({SELECT CustomerID, OrderID FROM Orders} AS CustomerOrders " &
        "RELATE CustomerID TO CustomerID)", connection)

        connection.Open()

        Using custReader As OleDbDataReader = custCMD.ExecuteReader()

            Do While custReader.Read()
                Console.WriteLine("Orders for " & custReader.GetString(1))
                ' custReader.GetString(1) = CompanyName  

                Using orderReader As OleDbDataReader = custReader.GetValue(2)
                    ' custReader.GetValue(2) = Orders chapter as DataReader  

                    Do While orderReader.Read()
                        Console.WriteLine(vbTab & orderReader.GetInt32(1))
                        ' orderReader.GetInt32(1) = OrderID  
                    Loop
                    orderReader.Close()
                End Using
            Loop
            ' Make sure to always close readers and connections.  
            custReader.Close()
        End Using
    End Using
End Using
using (OleDbConnection connection = new OleDbConnection(
    "Provider=MSDataShape;Data Provider=SQLOLEDB;" +
    "Data Source=localhost;Integrated Security=SSPI;Initial Catalog=northwind"))
{
    using (OleDbCommand custCMD = new OleDbCommand(
        "SHAPE {SELECT CustomerID, CompanyName FROM Customers} " +
        "APPEND ({SELECT CustomerID, OrderID FROM Orders} AS CustomerOrders " +
        "RELATE CustomerID TO CustomerID)", connection))
    {
        connection.Open();

        using (OleDbDataReader custReader = custCMD.ExecuteReader())
        {

            while (custReader.Read())
            {
                Console.WriteLine("Orders for " + custReader.GetString(1));
                // custReader.GetString(1) = CompanyName  

                using (OleDbDataReader orderReader = (OleDbDataReader)custReader.GetValue(2))
                {
                    // custReader.GetValue(2) = Orders chapter as DataReader  

                    while (orderReader.Read())
                        Console.WriteLine("\t" + orderReader.GetInt32(1));
                    // orderReader.GetInt32(1) = OrderID  
                    orderReader.Close();
                }
            }
            // Make sure to always close readers and connections.  
            custReader.Close();
        }
    }
}

Retour de résultats avec des REF CURSORS Oracle

Le fournisseur de données .NET Framework pour Oracle prend en charge l'utilisation des REF CURSOR Oracle pour retourner le résultat d'une requête. Un REF CURSOR Oracle est retourné en tant qu'objet OracleDataReader.

Vous pouvez récupérer un objet OracleDataReader qui représente un REF CURSOR Oracle en utilisant la méthode ExecuteReader. Vous pouvez aussi spécifier un OracleCommand qui retourne un ou plusieurs REF CURSORS Oracle en tant que SelectCommand pour un OracleDataAdapter utilisé pour remplir un DataSet.

Pour accéder à un REF CURSOR retourné par une source de données Oracle, créez une OracleCommand pour votre requête et ajoutez un paramètre de sortie qui référence le REF CURSOR à la collection Parameters de votre OracleCommand. Le nom du paramètre doit correspondre à celui du paramètre REF CURSOR de votre requête. Définissez le type du paramètre sur OracleType.Cursor. La méthode OracleCommand.ExecuteReader() de votre OracleCommand retourne un OracleDataReader pour le REF CURSOR.

Si votre OracleCommand retourne plusieurs REF CURSORS, ajoutez plusieurs paramètres de sortie. Vous pouvez accéder aux différents REF CURSORS en appelant la méthode OracleCommand.ExecuteReader(). L’appel à ExecuteReader() retourne un OracleDataReader qui référence le premier REF CURSOR. Vous pouvez ensuite appeler la méthode OracleDataReader.NextResult() pour accéder aux REF CURSORS suivants. Bien que les paramètres de votre collection OracleCommand.Parameters correspondent par leur nom aux paramètres de sortie du REF CURSOR, le OracleDataReader y accède selon l’ordre de leur ajout à la collection Parameters.

Considérez, par exemple, le package et le corps de package Oracle suivants.

CREATE OR REPLACE PACKAGE CURSPKG AS
  TYPE T_CURSOR IS REF CURSOR;
  PROCEDURE OPEN_TWO_CURSORS (EMPCURSOR OUT T_CURSOR,
    DEPTCURSOR OUT T_CURSOR);
END CURSPKG;  
  
CREATE OR REPLACE PACKAGE BODY CURSPKG AS
  PROCEDURE OPEN_TWO_CURSORS (EMPCURSOR OUT T_CURSOR,
    DEPTCURSOR OUT T_CURSOR)
  IS
  BEGIN
    OPEN EMPCURSOR FOR SELECT * FROM DEMO.EMPLOYEE;
    OPEN DEPTCURSOR FOR SELECT * FROM DEMO.DEPARTMENT;
  END OPEN_TWO_CURSORS;
END CURSPKG;

Le code suivant crée une OracleCommand qui retourne les REF CURSORS du package Oracle précédent en ajoutant deux paramètres de type OracleType.Cursor à la collection OracleCommand.Parameters.

Dim cursCmd As OracleCommand = New OracleCommand("CURSPKG.OPEN_TWO_CURSORS", oraConn)  
cursCmd.Parameters.Add("EMPCURSOR", OracleType.Cursor).Direction = ParameterDirection.Output  
cursCmd.Parameters.Add("DEPTCURSOR", OracleType.Cursor).Direction = ParameterDirection.Output  
OracleCommand cursCmd = new OracleCommand("CURSPKG.OPEN_TWO_CURSORS", oraConn);  
cursCmd.Parameters.Add("EMPCURSOR", OracleType.Cursor).Direction = ParameterDirection.Output;  
cursCmd.Parameters.Add("DEPTCURSOR", OracleType.Cursor).Direction = ParameterDirection.Output;  

Le code suivant retourne les résultats de la commande précédente en utilisant les méthodes Read()et NextResult() du OracleDataReader. Les paramètres REF CURSOR sont retournés dans l'ordre.

oraConn.Open()  
  
Dim cursCmd As OracleCommand = New OracleCommand("CURSPKG.OPEN_TWO_CURSORS", oraConn)  
cursCmd.CommandType = CommandType.StoredProcedure  
cursCmd.Parameters.Add("EMPCURSOR", OracleType.Cursor).Direction = ParameterDirection.Output  
cursCmd.Parameters.Add("DEPTCURSOR", OracleType.Cursor).Direction = ParameterDirection.Output  
  
Dim reader As OracleDataReader = cursCmd.ExecuteReader()  
  
Console.WriteLine(vbCrLf & "Emp ID" & vbTab & "Name")  
  
Do While reader.Read()  
  Console.WriteLine("{0}" & vbTab & "{1}, {2}", reader.GetOracleNumber(0), reader.GetString(1), reader.GetString(2))  
Loop  
  
reader.NextResult()  
  
Console.WriteLine(vbCrLf & "Dept ID" & vbTab & "Name")  
  
Do While reader.Read()  
  Console.WriteLine("{0}" & vbTab & "{1}", reader.GetOracleNumber(0), reader.GetString(1))  
Loop  
' Make sure to always close readers and connections.  
reader.Close()  
oraConn.Close()  
oraConn.Open();  
  
OracleCommand cursCmd = new OracleCommand("CURSPKG.OPEN_TWO_CURSORS", oraConn);  
cursCmd.CommandType = CommandType.StoredProcedure;  
cursCmd.Parameters.Add("EMPCURSOR", OracleType.Cursor).Direction = ParameterDirection.Output;  
cursCmd.Parameters.Add("DEPTCURSOR", OracleType.Cursor).Direction = ParameterDirection.Output;  
  
OracleDataReader reader = cursCmd.ExecuteReader();  
  
Console.WriteLine("\nEmp ID\tName");  
  
while (reader.Read())  
  Console.WriteLine("{0}\t{1}, {2}", reader.GetOracleNumber(0), reader.GetString(1), reader.GetString(2));  
  
reader.NextResult();  
  
Console.WriteLine("\nDept ID\tName");  
  
while (reader.Read())  
  Console.WriteLine("{0}\t{1}", reader.GetOracleNumber(0), reader.GetString(1));  
// Make sure to always close readers and connections.  
reader.Close();  
oraConn.Close();  

L’exemple suivant utilise la commande précédente pour remplir un DataSet avec les résultats du package Oracle.

Dim ds As DataSet = New DataSet()  
  
Dim adapter As OracleDataAdapter = New OracleDataAdapter(cursCmd)  
adapter.TableMappings.Add("Table", "Employees")  
adapter.TableMappings.Add("Table1", "Departments")  
  
adapter.Fill(ds)  
DataSet ds = new DataSet();  
  
OracleDataAdapter adapter = new OracleDataAdapter(cursCmd);  
adapter.TableMappings.Add("Table", "Employees");  
adapter.TableMappings.Add("Table1", "Departments");  
  
adapter.Fill(ds);  

Notes

Pour éviter une OverflowException, nous vous recommandons également d’effectuer les conversions du type Oracle NUMBER en un type .NET Framework valide avant de stocker la valeur dans un DataRow. Vous pouvez utiliser l’événement FillError pour déterminer si une exception OverflowException s’est produite. Pour plus d’informations sur l’événement FillError, consultez Gestion des événements DataAdapter.

Voir aussi