Share via


Extraction des données à l'aide de DataReader

Vous pouvez utiliser le DataReader ADO.NET pour extraire d'une base de données un flux de données en lecture seule et avant uniquement. Les résultats sont retournés pendant que la requête s'exécute et stockés dans la mémoire tampon de réseau sur le client jusqu'à ce que vous les demandiez au moyen de la méthode Read de DataReader. L'utilisation de DataReader peut augmenter les performances de l'application d'abord en extrayant les données dès qu'elles sont disponibles, plutôt que d'attendre que tous les résultats de la requête aient été retournés, et ensuite en ne stockant (par défaut) qu'une seule ligne à la fois dans la mémoire, ce qui réduit la charge du système.

Après avoir créé une instance de l'objet Command, vous créez un DataReader en appelant Command.ExecuteReader pour extraire les lignes d'une source de données, comme le montre l'exemple suivant.

Dim myReader As SqlDataReader = myCommand.ExecuteReader()
[C#]
SqlDataReader myReader = myCommand.ExecuteReader();

Vous utilisez la méthode Read de l'objet DataReader 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 une meilleure performance, le DataReader fournit une série de méthodes qui vous permettent d'accéder aux valeurs de colonnes dans leurs types de données natifs (GetDateTime, GetDouble, GetGuid, GetInt32, etc.). Pour obtenir une liste des méthodes d'accesseurs typées, consultez OleDbDataReader, classe et SqlDataReader, classe. L'utilisation des méthodes d'accesseurs typées lorsque le type de données sous-jacent est connu réduit le volume de conversion de types requise lors de l'extraction de la valeur de colonne.

Remarque   La version 1.1 du .NET Framework inclut une propriété supplémentaire pour le DataReader, HasRows, laquelle vous permet de déterminer si le DataReader a retourné des résultats avant de le lire.

L'exemple de code suivant itère dans un objet DataReader et retourne deux colonnes à partir de chaque ligne.

If myReader.HasRows Then
  Do While myReader.Read()
    Console.WriteLine(vbTab & "{0}" & vbTab & "{1}", myReader.GetInt32(0), myReader.GetString(1))
  Loop
Else
  Console.WriteLine("No rows returned.")
End If

myReader.Close()
[C#]
if (myReader.HasRows)
  while (myReader.Read())
    Console.WriteLine("\t{0}\t{1}", myReader.GetInt32(0), myReader.GetString(1));
else
  Console.WriteLine("No rows returned.");

myReader.Close();

Le DataReader fournit un flux de données non mis en 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 lors de l'extraction de grandes quantités de données car celles-ci ne sont pas mises en cache dans la mémoire.

Fermeture du DataReader

Vous devez toujours appeler la méthode Close lorsque vous avez fini d'utiliser l'objet DataReader.

Si Command contient des paramètres de sortie ou des valeurs de retour, ils ne seront pas disponibles avant la fermeture du DataReader.

Notez que pendant l'ouverture d'un DataReader, Connection est utilisé en mode exclusif par ce DataReader. Vous ne pourrez pas exécuter les commandes pour Connection, y compris la création d'un autre DataReader, jusqu'à la fermeture du DataReader d'origine.

Remarque   N'appelez pas Close ou Dispose sur un objet Connection, DataReader ou tout autre objet managé 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 managées, n'incluez pas la méthode Finalize dans votre définition de classe. Pour plus d'informations, consultez Programmation d'un garbage collection.

Jeux de résultats multiples

Si des jeux de résultats multiples sont retournés, le DataReader fournit la méthode NextResult pour itérer sur les jeux de résultats dans l'ordre, comme cela est illustré dans l'exemple de code suivant.

Dim myCMD As SqlCommand = New SqlCommand("SELECT CategoryID, CategoryName FROM Categories;" & _
                                         "SELECT EmployeeID, LastName FROM Employees", nwindConn)
nwindConn.Open()

Dim myReader As SqlDataReader = myCMD.ExecuteReader()

Dim fNextResult As Boolean = True
Do Until Not fNextResult
  Console.WriteLine(vbTab & myReader.GetName(0) & vbTab & myReader.GetName(1))

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

  fNextResult = myReader.NextResult()
Loop

myReader.Close()
nwindConn.Close()
[C#]
SqlCommand myCMD = new SqlCommand("SELECT CategoryID, CategoryName FROM Categories;" +
                                  "SELECT EmployeeID, LastName FROM Employees", nwindConn);
nwindConn.Open();

SqlDataReader myReader = myCMD.ExecuteReader();

do
{
  Console.WriteLine("\t{0}\t{1}", myReader.GetName(0), myReader.GetName(1));

  while (myReader.Read())
    Console.WriteLine("\t{0}\t{1}", myReader.GetInt32(0), myReader.GetString(1));

} while (myReader.NextResult());

myReader.Close();
nwindConn.Close();

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

Lorsqu'un DataReader est ouvert, vous pouvez extraire des informations de schéma concernant le jeu de résultats actuel à l'aide de 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 actuel. Le DataTable contiendra une ligne pour chaque colonne du jeu de résultats. Chaque colonne de la ligne de table de schéma mappe à une propriété de la colonne retournée dans le jeu de résultats, où ColumnName est le nom de la propriété et 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.

Dim schemaTable As DataTable = myReader.GetSchemaTable()

Dim myRow As DataRow
Dim myCol As DataColumn

For Each myRow In schemaTable.Rows
  For Each myCol In schemaTable.Columns
    Console.WriteLine(myCol.ColumnName & " = " & myRow(myCol).ToString())
  Next
  Console.WriteLine()
Next
[C#]
DataTable schemaTable = myReader.GetSchemaTable();

foreach (DataRow myRow in schemaTable.Rows)
{
  foreach (DataColumn myCol in schemaTable.Columns)
    Console.WriteLine(myCol.ColumnName + " = " + myRow[myCol]);
  Console.WriteLine();
}

Chapitres OLE DB

Les jeux de lignes ou chapitres hiérarchiques (DBTYPE_HCHAPTER de type OLE DB, adChapter de type ADO) peuvent être extraits à l'aide de OleDbDataReader. Lorsqu'une requête comprenant un chapitre est retournée comme DataReader, le chapitre est retourné comme colonne dans ce DataReader et exposé comme objet DataReader.

Le DataSet ADO.NET peut aussi être utilisé pour représenter des jeux de lignes hiérarchiques à l'aide de relations parent-enfant entre les tables. Pour plus d'informations, consultez Création et utilisation de DataSets.

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.

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

Dim custCMD As OleDbCommand = New OleDbCommand("SHAPE {SELECT CustomerID, CompanyName FROM Customers} " & _
                                         "  APPEND ({SELECT CustomerID, OrderID FROM Orders} AS CustomerOrders " & _
                                         "  RELATE CustomerID TO CustomerID)", nwindConn)
nwindConn.Open()

Dim custReader As OleDbDataReader = custCMD.ExecuteReader()
Dim orderReader As OleDbDataReader

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

  orderReader = 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()
Loop

custReader.Close()
nwindConn.Close()
[C#]
OleDbConnection nwindConn = new OleDbConnection("Provider=MSDataShape;Data Provider=SQLOLEDB;" +
                                                "Data Source=localhost;Integrated Security=SSPI;Initial Catalog=northwind");

OleDbCommand custCMD = new OleDbCommand("SHAPE {SELECT CustomerID, CompanyName FROM Customers} " +
                                      "  APPEND ({SELECT CustomerID, OrderID FROM Orders} AS CustomerOrders " +
                                      "  RELATE CustomerID TO CustomerID)", nwindConn);
nwindConn.Open();

OleDbDataReader custReader = custCMD.ExecuteReader();
OleDbDataReader orderReader;

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

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

custReader.Close();
nwindConn.Close();

REF CURSOR 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 que OracleDataReader.

Vous pouvez extraire un objet OracleDataReader qui représente un REF CURSOR Oracle à l'aide de la méthode OracleCommand.ExecuteReader et également spécifier un OracleCommand qui retourne un ou plusieurs REF CURSOR Oracle en tant que SelectCommand d'un objet OracleDataAdapter utilisé pour remplir un DataSet.

Pour accéder à un REF CURSOR retourné d'une source de données Oracle, créez un 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 au paramètre REF CURSOR de votre requête. Affectez au paramètre le type OracleType.Cursor. La méthode ExecuteReader de votre OracleCommand retournera un OracleDataReader pour le REF CURSOR.

Si votre OracleCommand retourne plusieurs REF CURSOR, ajoutez plusieurs paramètres de sortie. Vous pouvez accéder aux différents REF CURSOR en appelant la méthode OracleCommand.ExecuteReader. L'appel à la méthode 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 CURSOR suivants. Bien que les paramètres de votre collection OracleCommand.Parameters coïncident par leur nom avec les 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 un OracleCommand qui retourne les REF CURSOR d'un précédent package Oracle en ajoutant deux paramètres de type OracleType.Cursor à la collection 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
[C#]
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 précédente commande à l'aide des méthodes Read et NextResult de 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 rdr As OracleDataReader = cursCmd.ExecuteReader()

Console.WriteLine(vbCrLf & "Emp ID" & vbTab & "Name")

Do While rdr.Read()
  Console.WriteLine("{0}" & vbTab & "{1}, {2}", rdr.GetOracleNumber(0), rdr.GetString(1), rdr.GetString(2))
Loop

rdr.NextResult()

Console.WriteLine(vbCrLf & "Dept ID" & vbTab & "Name")

Do While rdr.Read()
  Console.WriteLine("{0}" & vbTab & "{1}", rdr.GetOracleNumber(0), rdr.GetString(1))
Loop

rdr.Close()
oraConn.Close()
[C#]
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 rdr = cursCmd.ExecuteReader();

Console.WriteLine("\nEmp ID\tName");

while (rdr.Read())
  Console.WriteLine("{0}\t{1}, {2}", rdr.GetOracleNumber(0), rdr.GetString(1), rdr.GetString(2));

rdr.NextResult();

Console.WriteLine("\nDept ID\tName");

while (rdr.Read())
  Console.WriteLine("{0}\t{1}", rdr.GetOracleNumber(0), rdr.GetString(1));

rdr.Close();
oraConn.Close();

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

**Remarque   **Il est conseillé de convertir tout type NUMBER Oracle en un type .NET Framework valide avant de stocker la valeur dans un DataRow pour éviter une exception OverflowException. 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 Utilisation des événements du DataAdapter.

Dim ds As DataSet = New DataSet()

Dim oraDa As OracleDataAdapter = New OracleDataAdapter(cursCmd)
oraDa.TableMappings.Add("Table", "Employees")
oraDa.TableMappings.Add("Table1", "Departments")

oraDa.Fill(ds)
[C#]
DataSet ds = new DataSet();

OracleDataAdapter oraDa = new OracleDataAdapter(cursCmd);
oraDa.TableMappings.Add("Table", "Employees");
oraDa.TableMappings.Add("Table1", "Departments");

oraDa.Fill(ds);

Voir aussi

Utilisation des fournisseurs de données .NET Framework pour l'accès aux données | DataTable, classe | OleDbDataReader, classe | SqlDataReader, classe