DataReader检索数据

使用 DataReader 检索数据

使用 DataReader 检索数据包括创建 Command 对象的实例,然后通过调用 Command.ExecuteReader 创建一个 DataReader,以便从数据源检索行。以下示例说明如何使用 SqlDataReader,其中 command 代表有效的 SqlCommand 对象。

[Visual Basic]

复制代码
Dim reader As SqlDataReader = command.ExecuteReader()

[C#]

复制代码
SqlDataReader reader = command.ExecuteReader();

使用 DataReader 对象的 Read 方法可从查询结果中获取行。通过向 DataReader 传递列的名称或序号引用,可以访问返回行的每一列。不过,为了实现最佳性能,DataReader 提供了一系列方法,将使您能够访问其本机数据类型(GetDateTime、GetDouble、GetGuid、GetInt32 等)的列值。有关数据提供程序特定的 DataReaders 的类型化访问器方法列表,请参见 OleDbDataReader 和 SqlDataReader。假定基础数据类型为已知,如果使用类型化访问器方法,将减少在检索列值时所需的类型转换量。

Note注意

.NET Framework 的 Windows Server 2003 版包含 DataReader 的附加属性 HasRows,该属性使您能够在读取 DataReader 之前就可确定它是否返回了任何结果。

以下代码示例循环访问一个 DataReader 对象,并从每个行中返回两个列。

[Visual Basic]

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

reader.Close()

[C#]

复制代码
if (reader.HasRows)
  while (reader.Read())
    Console.WriteLine("/t{0}/t{1}", reader.GetInt32(0), reader.GetString(1));
else
  Console.WriteLine("No rows returned.");

reader.Close();

DataReader 提供未缓冲的数据流,该数据流使过程逻辑可以有效地按顺序处理从数据源中返回的结果。由于数据不在内存中缓存,所以在检索大量数据时,DataReader 是一种适合的选择。

关闭 DataReader

每次使用完 DataReader 对象后都应调用 Close 方法。

如果 Command 包含输出参数或返回值,那么在 DataReader 关闭之前,将无法访问这些输出参数或返回值。

请注意,当 DataReader 打开时,该 DataReader 将以独占方式使用 Connection。在原始 DataReader 关闭之前,将无法对 Connection 执行任何命令(包括创建另一个 DataReader)。

Note注意

不要在类的 Finalize 方法中对 Connection、DataReader 或任何其他托管对象调用 Close 或 Dispose。在终结器中,仅释放类直接拥有的非托管资源。如果类不拥有任何非托管资源,则不要在类定义中包含 Finalize 方法。有关更多信息,请参见 垃圾回收。

多个结果集

如果返回的是多个结果集,DataReader 会提供 NextResult 方法来按顺序循环访问这些结果集。以下示例显示 SqlDataReader 如何使用 ExecuteReader 方法处理两个 SELECT 语句的结果。

[Visual Basic]

复制代码
' Assumes that connection is a valid SqlConnection object.
Dim command As SqlCommand = New SqlCommand( _
  "SELECT CategoryID, CategoryName FROM dbo.Categories;" & _
  "SELECT EmployeeID, LastName FROM dbo.Employees", connection)
connection.Open()

Dim reader As SqlDataReader = command.ExecuteReader()

Dim nextResult As Boolean = True
Do Until Not nextResult
  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

  nextResult = reader.NextResult()
Loop

reader.Close()
connection.Close()

[C#]

复制代码
// Assumes that connection is a valid SqlConnection object.
SqlCommand command = new SqlCommand(
  "SELECT CategoryID, CategoryName FROM dbo.Categories;" +
  "SELECT EmployeeID, LastName FROM dbo.Employees", connection);
connection.Open();

SqlDataReader reader = command.ExecuteReader();

do
{
  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));

} while (reader.NextResult());

reader.Close();
connection.Close();

从 DataReader 中获取架构信息

当 DataReader 打开时,可以使用 GetSchemaTable 方法检索有关当前结果集的架构信息。GetSchemaTable 将返回一个填充了行和列的 DataTable 对象,这些行和列包含当前结果集的架构信息。对于结果集的每一列,DataTable 都包含一行。架构表行的每一列都映射到在结果集中返回的列的属性,其中 ColumnName 是属性的名称,而列的值为属性的值。以下代码示例为 DataReader 编写架构信息。

[Visual Basic]

复制代码
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(column.ColumnName & " = " & row(column).ToString())
  Next
  Console.WriteLine()
Next

[C#]

复制代码
DataTable schemaTable = reader.GetSchemaTable();

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

OLE DB 章节

分层行集或章节(OLE DB 类型 DBTYPE_HCHAPTER、ADO 类型 adChapter)可以使用 OleDbDataReader 来检索。当以 DataReader 的形式返回包含某章节的查询时,该章节将以此 DataReader 中列的形式返回,并作为 DataReader 对象公开。

ADO.NET DataSet 也可用于通过表间的父子关系来表示分层行集。有关更多信息,请参见 在 ADO.NET 中使用 DataSet。

以下代码示例使用 MSDataShape 提供程序来为客户列表中的每个客户生成订单的章节列。

[Visual Basic]

复制代码
Dim connection 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)", connection)
connection.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()
connection.Close()

[C#]

复制代码
OleDbConnection connection = 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)", connection);
connection.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();
connection.Close();

Oracle REF CURSOR

Oracle .NET Framework 数据提供程序支持使用 Oracle REF CURSOR 返回查询结果。Oracle REF CURSOR 以 OracleDataReader 的形式返回。

可以使用 ExecuteReader 方法检索表示 Oracle REF CURSOR 的 OracleDataReader 对象,也可以将返回一个或多个 Oracle REF CURSOR 的 OracleCommand 指定为用于填充 DataSet 的 OracleDataAdapter 的 SelectCommand。

若要访问从 Oracle 数据源中返回的 REF CURSOR,请为查询创建 OracleCommand,并将引用 REF CURSOR 的输出参数添加到 OracleCommand 的 Parameters 集合中。该参数的名称必须与查询中的 REF CURSOR 参数名称相匹配。将参数类型设置为 OracleType.Cursor。OracleCommand 的 ExecuteReader 方法将为 REF CURSOR 返回 OracleDataReader。

如果 OracleCommand 返回多个 REF CURSOR,则将添加多个输出参数。通过调用 OracleCommand.ExecuteReader 方法可以访问不同的 REF CURSOR。调用 ExecuteReader 将返回引用第一个 REF CURSOR 的 OracleDataReader。然后,可以调用 OracleDataReader.NextResult 方法访问随后的 REF CURSOR。尽管 OracleCommand.Parameters 集合中参数的名称与 REF CURSOR 输出参数名称相匹配,但 OracleDataReader 将按这些参数添加到 Parameters 集合中的顺序进行访问。

例如,请看下面这个 Oracle 包和包正文。

复制代码
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; 

以下代码将创建从先前的 Oracle 包返回 REF CURSOR 的 OracleCommand,方法是将类型 OracleType.Cursor 的两个参数添加到 Parameters 集合中。

[Visual Basic]

复制代码
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;

以下代码使用 OracleDataReader 的 Read 和 NextResult 方法返回先前命令的结果。REF CURSOR 参数按顺序返回。

[Visual Basic]

复制代码
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

reader.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 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));

reader.Close();
oraConn.Close();

以下示例使用先前的命令用 Oracle 包的结果来填充 DataSet。

Note注意

为了避免 OverflowException,建议您在将值存储在 DataRow 中之前,还应执行从 Oracle NUMBER 类型到有效的 .NET Framework 类型的任何转换。可以使用 FillError 事件来确定是否发生了 OverflowException。有关 FillError 事件的更多信息,请参见 使用 DataAdapter 事件。

[Visual Basic]

 
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)

[C#]

 
DataSet ds = new DataSet();

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

adapter.Fill(ds);

你可能感兴趣的:(DataReader检索数据)