The DataAdapter object is a key component in ADO.NET, acting as a bridge between a Dataset and a data source. Its primary role is to retrieve data from the data source and populate a Dataset, and then to reconcile changes made in the Dataset back to the data source.
Core Functionality
DataAdapter objects abstract the underlying data provider. For example, SqlDataAdapter works with SQL Server, while OdbcDataAdapter works with ODBC-compliant data sources.
The main operations performed by a DataAdapter are:
- Fill: Populates a
Datasetwith data from a data source. - Update: Propagates changes made to a
Datasetback to the data source. - SelectCommand: Retrieves data.
- InsertCommand: Inserts new rows.
- UpdateCommand: Updates existing rows.
- DeleteCommand: Deletes rows.
Key Classes
The ADO.NET data providers implement concrete classes for DataAdapter. The most common ones include:
System.Data.SqlClient.SqlDataAdapterfor SQL Server.System.Data.OleDb.OleDbDataAdapterfor OLE DB providers.System.Data.Odbc.OdbcDataAdapterfor ODBC data sources.System.Data.OracleClient.OracleDataAdapterfor Oracle databases.
Using DataAdapter
The typical workflow involves:
- Creating a
Connectionobject to your data source. - Creating a
Commandobject to execute a query or stored procedure. - Creating a
DataAdapterobject, passing theCommandandConnectionto its constructor or setting their properties. - Creating a
Datasetobject. - Calling the
Fill()method of theDataAdapter, passing theDatasetand the name of the table to populate. - After making modifications to the
Dataset, calling theUpdate()method of theDataAdapter, passing theDataset.
Example: Filling a Dataset
using System;
using System.Data;
using System.Data.SqlClient;
// ...
using (SqlConnection connection = new SqlConnection("YourConnectionString"))
{
SqlDataAdapter adapter = new SqlDataAdapter("SELECT * FROM Customers", connection);
DataSet dataSet = new DataSet();
connection.Open();
adapter.Fill(dataSet, "Customers");
connection.Close();
// Now you can work with the data in dataSet.Tables["Customers"]
foreach (DataRow row in dataSet.Tables["Customers"].Rows)
{
Console.WriteLine(row["CustomerID"] + " - " + row["CompanyName"]);
}
}
Example: Updating a Dataset
using System;
using System.Data;
using System.Data.SqlClient;
// ... Assuming dataSet is already populated and modified
using (SqlConnection connection = new SqlConnection("YourConnectionString"))
{
SqlDataAdapter adapter = new SqlDataAdapter("SELECT CustomerID, CompanyName FROM Customers", connection);
// Configure the UpdateCommand for the Customers table
adapter.UpdateCommand = new SqlCommand("UPDATE Customers SET CompanyName = @CompanyName WHERE CustomerID = @CustomerID", connection);
adapter.UpdateCommand.Parameters.Add("@CompanyName", SqlDbType.VarChar, 50, "CompanyName");
adapter.UpdateCommand.Parameters.Add("@CustomerID", SqlDbType.Int, 0, "CustomerID");
connection.Open();
int rowsAffected = adapter.Update(dataSet, "Customers");
connection.Close();
Console.WriteLine($"{rowsAffected} rows updated.");
}
Handling Updates
The Update() method uses the InsertCommand, UpdateCommand, and DeleteCommand properties to apply changes. If these commands are not set, the Update() method will throw an exception. The DataAdapter automatically detects the state of each row (Added, Modified, Deleted) and executes the appropriate command.
Note: When using UpdateCommand, InsertCommand, or DeleteCommand, you must define the parameters correctly, mapping them to the columns in your Dataset using the SourceColumn property.
DataAdapter Events
DataAdapter objects expose several events that allow you to intervene in the data retrieval and update process:
RowUpdating: Fired before a row is updated.RowUpdated: Fired after a row has been updated.FillUpdating: Fired before the entire fill operation.FillUpdated: Fired after the entire fill operation.
Advantages of DataAdapter
- Abstraction: Hides the complexities of the data provider.
- Efficiency: Optimized for batch operations.
- Flexibility: Works seamlessly with
Datasetobjects for disconnected data scenarios.
Tip: For simple data retrieval where updates are not required, a DataReader is often more efficient as it provides a forward-only, read-only stream of data.