DataReader를 사용하여 데이터를 검색하려면 Command 개체의 인스턴스를 만든 다음, Command.ExecuteReader를 호출하여 데이터 원본에서 행을 검색하여 DataReader를 만듭니다. DataReader는 절차 논리가 데이터 원본의 결과를 순차적으로 효율적으로 처리할 수 있도록 하는 버퍼되지 않은 데이터 스트림을 제공합니다. 데이터가 메모리에 캐시되지 않으므로 많은 양의 데이터를 검색할 때 DataReader 를 선택하는 것이 좋습니다.
다음 예제에서는 유효한 DataReaderreader
를 나타내고 command
유효한 Command 개체를 나타내는 DataReader를 사용하는 방법을 보여 줍니다.
reader = command.ExecuteReader();
reader = command.ExecuteReader()
DataReader.Read 메서드를 사용하여 쿼리 결과에서 행을 가져옵니다. 열의 이름 또는 서수 번호를 DataReader에 전달하여 반환된 행의 각 열에 액세스할 수 있습니다. 그러나 최상의 성능을 위해 DataReader 는 네이티브 데이터 형식(GetDateTime, GetDouble, GetGuid, GetInt32 등)의 열 값에 액세스할 수 있는 일련의 메서드를 제공합니다. 데이터 공급자별 DataReaders에 대한 형식화된 접근자 메서드 목록은 다음을 참조 OleDbDataReader 하세요 SqlDataReader. 기본 데이터 형식을 알고 있는 경우 형식화된 접근자 메서드를 사용하면 열 값을 검색할 때 필요한 형식 변환의 양이 줄어듭니다.
다음 예제에서는 DataReader 개체를 반복하고 각 행에서 두 개의 열을 반환합니다.
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($"{reader.GetInt32(0)}\t{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
DataReader 닫기
DataReader 개체 사용을 마쳤으면 항상 Close 메서드를 호출합니다.
명령에 출력 매개 변수 또는 반환 값이 포함된 경우 DataReader를 닫을 때까지 해당 값을 사용할 수 없습니다.
DataReader가 열려 있는 동안 해당 DataReader에서만 연결이 사용되고 있습니다. 원래 DataReader를 닫을 때까지 다른 DataReader 만들기를 포함하여 연결에 대한 명령을 실행할 수 없습니다.
비고
연결, DataReader 또는 클래스의 Finalize 메서드에서 다른 관리되는 개체에 대해 Close 또는 Dispose를 호출하지 마세요. 종료자에서는 여러분의 클래스가 직접 소유한 관리되지 않는 리소스만 해제합니다. 클래스가 관리되지 않는 리소스를 소유하지 않는 경우 클래스 정의에 Finalize 메서드를 포함하지 마세요. 자세한 내용은 가비지 컬렉션을 참조하세요.
NextResult를 사용하여 여러 결과 집합 검색
DataReader가 여러 결과 집합을 반환하는 경우 NextResult 메서드를 호출하여 결과 집합을 순차적으로 반복합니다. 다음 예제에서는 SqlDataReader 메서드를 사용하여 두 SELECT 문의 결과를 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{reader.GetName(0)}\t{reader.GetName(1)}");
while (reader.Read())
{
Console.WriteLine($"\t{reader.GetInt32(0)}\t{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
DataReader에서 스키마 정보 가져오기
DataReader가 열려 있는 동안 GetSchemaTable 메서드를 사용하여 현재 결과 집합에 대한 스키마 정보를 검색할 수 있습니다. GetSchemaTable 은 DataTable 현재 결과 집합에 대한 스키마 정보를 포함하는 행 및 열로 채워진 개체를 반환합니다. DataTable은 결과 집합의 각 열에 대해 하나의 행을 포함합니다. 스키마 테이블의 각 열은 결과 집합의 행에서 반환된 열의 속성에 매핑됩니다. 여기서 ColumnName 은 속성의 이름이고 열 값은 속성 값입니다. 다음 예제에서는 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
OLE DB 챕터 작업
계층적 행 집합 또는 장(OLE DB 형식 DBTYPE_HCHAPTER, ADO 형식 adChapter)을 사용하여 OleDbDataReader검색할 수 있습니다. 장을 포함하는 쿼리가 DataReader로 반환되면 해당 챕터가 해당 DataReader 의 열로 반환되고 DataReader 개체로 노출됩니다.
ADO.NET DataSet 을 사용하여 테이블 간의 부모-자식 관계를 사용하여 계층적 행 집합을 나타낼 수도 있습니다. 자세한 내용은 DataSets, DataTables 및 DataViews를 참조하세요.
다음 코드 예제에서는 MSDataShape 공급자를 사용하여 고객 목록에서 각 고객에 대한 주문 장 열을 생성합니다.
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();
}
}
}
Oracle REF CURSOR을 사용하여 결과 반환
.NET Framework Data Provider for Oracle은 Oracle REF CURSOR을 사용하여 쿼리 결과를 반환하도록 지원합니다. Oracle REF CURSOR가 . OracleDataReader로 반환됩니다.
OracleDataReader 메서드를 사용하여 Oracle REF CURSOR를 나타내는 ExecuteReader 객체를 검색할 수 있습니다. Oracle REF CURSOR 하나 이상을 반환하는 OracleCommand을 SelectCommand으로 지정하여 OracleDataAdapter을 사용하면 DataSet을 채울 수 있습니다.
Oracle 데이터 원본에서 반환된 REF CURSOR에 액세스하려면 쿼리를 위한 OracleCommand을 생성하고, REF CURSOR를 참조하는 출력 매개 변수를 Parameters의 OracleCommand 컬렉션에 추가합니다. 매개 변수의 이름은 쿼리의 REF CURSOR 매개 변수 이름과 일치해야 합니다. 매개 변수의 형식을 .로 OracleType.Cursor설정합니다. OracleCommand.ExecuteReader()의 OracleCommand 메서드는 REF CURSOR에 대한 OracleDataReader를 반환합니다.
여러 REF CURSORS를 반환하는 OracleCommand 경우 여러 출력 매개 변수를 추가합니다. 메서드를 호출 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;
다음 코드는 컬렉션에 OracleCommand 형식 OracleType.Cursor 의 두 매개 변수를 추가하여 이전 Oracle 패키지에서 REF CURSOR을 반환하는 형식을 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;
다음 코드는 의 메서드 및 메서드를 Read() 사용하여 이전 명령의 NextResult()결과를 반환합니다OracleDataReader. REF CURSOR 매개 변수가 순서대로 반환됩니다.
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();
다음 예제에서는 이전 명령을 사용하여 Oracle 패키지의 결과로 채웁다 DataSet .
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);
비고
OverflowException을 방지하려면 값을 DataRow저장하기 전에 Oracle NUMBER 형식에서 유효한 .NET Framework 형식으로의 변환도 처리하는 것이 좋습니다. 이벤트를 FillError 사용하여 OverflowException 이 발생했는지 확인할 수 있습니다. 이벤트에 대한 FillError 자세한 내용은 DataAdapter 이벤트 처리를 참조하세요.