Commands and DataReaders
ADO.NET provides objects to interact with data sources. At the core of data manipulation are Command objects, used to execute SQL statements or stored procedures, and DataReader objects, used for efficient, forward-only, read-only access to data.
DbCommand Objects
The DbCommand class (and its provider-specific subclasses like SqlCommand for SQL Server or OracleCommand for Oracle) represents an SQL statement or stored procedure to be executed against a data source.
Key Properties:
CommandText: The SQL statement or stored procedure name.CommandType: Specifies whether theCommandTextis a stored procedure or a text command.Connection: TheDbConnectionobject associated with the command.Parameters: A collection ofDbParameterobjects for parameterized queries.
Executing Commands:
Commands can be executed in various ways:
ExecuteReader(): Returns aDataReaderobject for retrieving rows.ExecuteNonQuery(): Executes a SQL statement that returns no rows (e.g., INSERT, UPDATE, DELETE) and returns the number of rows affected.ExecuteScalar(): Executes a query and returns the value of the first column of the first row in the result set.ExecuteXmlReader(): Executes the command and returns anXmlReader.
Example: Executing a SELECT query
using (SqlConnection connection = new SqlConnection(connectionString))
{
string query = "SELECT CustomerID, CompanyName FROM Customers WHERE City = @City";
SqlCommand command = new SqlCommand(query, connection);
command.Parameters.AddWithValue("@City", "London");
connection.Open();
SqlDataReader reader = command.ExecuteReader();
while (reader.Read())
{
Console.WriteLine($"ID: {reader["CustomerID"]}, Name: {reader["CompanyName"]}");
}
reader.Close();
}
DbDataReader Objects
DbDataReader (and its provider-specific subclasses like SqlDataReader) provides a way to retrieve a forward-only stream of rows from a data source. It is the most efficient way to retrieve data because it reads data as it is returned from the database, without buffering the entire result set in memory.
Key Methods:
Read(): Advances theDataReaderto the next record. Returnstrueif there are more rows; otherwise,false.GetOrdinal(string fieldName): Gets the zero-based column ordinal of the specified column name.GetValue(int i): Gets the value of the specified column.IsDBNull(int i): Returns a boolean indicating whether the specified column contains a null value.
Accessing Data:
Data can be accessed by column ordinal or column name. It's generally recommended to use the column ordinal for performance, obtained using GetOrdinal.
int idOrdinal = reader.GetOrdinal("CustomerID");
int nameOrdinal = reader.GetOrdinal("CompanyName");
while (reader.Read())
{
if (!reader.IsDBNull(idOrdinal))
{
int customerId = reader.GetInt32(idOrdinal);
string companyName = reader.GetString(nameOrdinal);
Console.WriteLine($"ID: {customerId}, Name: {companyName}");
}
}
GetOrdinal to retrieve column ordinals once outside the loop and then use these ordinals to access column values. This avoids repeated string lookups within the loop.
Close() on the DataReader when you are finished with it, or use a using statement to ensure it is properly disposed of and the connection is released.