ADO.NET Tutorials

DataAdapter and DataSet in ADO.NET

The DataAdapter class in ADO.NET acts as a bridge between a DataSet and a data source. It provides a convenient way to retrieve data from a source and populate a DataSet, as well as to resolve changes made to the DataSet back to the data source. The primary classes representing DataAdapters are:

Key Concepts

Populating a DataSet

The Fill method of a DataAdapter is used to load data into a DataSet. It executes a SELECT statement and populates a specified table within the DataSet with the results.

C# Example:


using System;
using System.Data;
using System.Data.SqlClient; // Or OleDbConnection, etc.

public class DataAdapterExample
{
    public static void Main(string[] args)
    {
        string connectionString = "Your_Connection_String_Here";
        string query = "SELECT CustomerID, CompanyName FROM Customers";

        using (SqlConnection connection = new SqlConnection(connectionString))
        {
            SqlDataAdapter adapter = new SqlDataAdapter(query, connection);
            DataSet dataSet = new DataSet();

            try
            {
                connection.Open();
                adapter.Fill(dataSet, "Customers"); // Populates the 'Customers' table in the DataSet

                Console.WriteLine("Customers Data:");
                foreach (DataRow row in dataSet.Tables["Customers"].Rows)
                {
                    Console.WriteLine($"ID: {row["CustomerID"]}, Name: {row["CompanyName"]}");
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Error: {ex.Message}");
            }
        }
    }
}
                

Updating the Data Source

When you modify data within a DataSet (e.g., add, delete, or update rows), you can use the Update method of the DataAdapter to persist these changes back to the data source. The DataAdapter uses its associated InsertCommand, UpdateCommand, and DeleteCommand properties to perform these operations.

Important: Ensure that the InsertCommand, UpdateCommand, and DeleteCommand properties are properly configured on the DataAdapter for the Update method to work correctly.

C# Example (Updating):


// ... (Previous code to populate DataSet)

// Assume you've made changes to dataSet.Tables["Customers"]
// For example, updating a row:
if (dataSet.Tables["Customers"].Rows.Count > 0)
{
    DataRow rowToUpdate = dataSet.Tables["Customers"].Rows[0];
    rowToUpdate["CompanyName"] = "Updated Company Name";
}

// Configure the UpdateCommand
using (SqlConnection connection = new SqlConnection(connectionString))
{
    string updateQuery = "UPDATE Customers SET CompanyName = @CompanyName WHERE CustomerID = @CustomerID";
    SqlCommand updateCommand = new SqlCommand(updateQuery, connection);
    updateCommand.Parameters.Add("@CompanyName", SqlDbType.NVarChar, 50, "CompanyName");
    updateCommand.Parameters.Add("@CustomerID", SqlDbType.Int, 4, "CustomerID").SourceVersion = DataRowVersion.Original;

    SqlDataAdapter adapter = new SqlDataAdapter();
    adapter.UpdateCommand = updateCommand;

    // Optionally configure InsertCommand and DeleteCommand as well

    try
    {
        connection.Open();
        int rowsAffected = adapter.Update(dataSet, "Customers");
        Console.WriteLine($"Rows updated: {rowsAffected}");
    }
    catch (Exception ex)
    {
        Console.WriteLine($"Error updating: {ex.Message}");
    }
}
                

Mapping and CommandBuilder

RowUpdating and RowUpdated Events

The DataAdapter provides events like RowUpdating and RowUpdated that allow you to intercept the update process for each row. This is useful for implementing custom logic, error handling, or auditing.

CommandBuilder

For simplifying the creation of automatically generated INSERT, UPDATE, and DELETE commands, ADO.NET provides CommandBuilder classes (e.g., SqlCommandBuilder, OleDbCommandBuilder). These builders can infer the necessary SQL statements based on the schema of the DataAdapter's SelectCommand.

Tip: Using CommandBuilder can significantly reduce the amount of boilerplate code required for data updates, especially when dealing with simple scenarios.

C# Example (CommandBuilder):


using (SqlConnection connection = new SqlConnection(connectionString))
{
    string query = "SELECT CustomerID, CompanyName FROM Customers";
    SqlDataAdapter adapter = new SqlDataAdapter(query, connection);
    SqlCommandBuilder commandBuilder = new SqlCommandBuilder(adapter); // Automatically generates commands

    DataSet dataSet = new DataSet();
    connection.Open();
    adapter.Fill(dataSet, "Customers");

    // ... Make changes to the DataSet ...

    adapter.Update(dataSet, "Customers");
}
                

When to Use DataAdapters

Note: For scenarios where you only need to read data sequentially and don't require caching or updating, DataReader objects are generally more efficient.