MSDN Documentation

Microsoft Developer Network

Disconnected Data Access in ADO.NET

Disconnected data access in ADO.NET refers to a programming model where data is retrieved from a data source and then manipulated by the application without maintaining an active connection to the data source. This approach offers significant advantages in terms of scalability, performance, and responsiveness, especially in multi-tiered applications.

In the connected data access model, a connection to the data source is held open for the duration of the data operations. This can be a bottleneck, as it consumes resources on both the client and the server. With disconnected data access, you fetch data, close the connection, and then work with the data in memory. When you need to persist changes, you re-establish a connection to send the updated data back to the source.

Key Components for Disconnected Data Access

DataSet and DataTable

The primary classes facilitating disconnected data access are DataSet and DataTable. A DataSet can hold multiple DataTable objects, each representing a table of data. These objects act as in-memory caches of data that can be populated, modified, and then used to update the original data source.

DataAdapter

The DataAdapter classes (e.g., SqlDataAdapter, OleDbDataAdapter) are crucial for bridging the gap between the DataSet and the data source. A DataAdapter has properties to define the SQL statements or stored procedures for retrieving data (SelectCommand) and for updating the data source based on changes made to the DataSet (InsertCommand, UpdateCommand, DeleteCommand).

Command Objects

Command objects (e.g., SqlCommand, OleDbCommand) are used to execute SQL statements or call stored procedures. In the context of disconnected data access, they are primarily used to populate the DataAdapter's commands and to send updates back to the database.

The Process of Disconnected Data Access

  1. Create a DataSet: Instantiate a DataSet object to hold the retrieved data.
  2. Create a DataAdapter: Instantiate the appropriate DataAdapter for your data source and configure its SelectCommand to fetch the desired data.
  3. Populate the DataSet: Use the Fill() method of the DataAdapter to load data from the data source into the DataSet. The connection is opened, data is fetched, and then the connection is closed by the DataAdapter.
  4. Modify Data (Client-side): Work with the data in the DataSet's DataTable objects. You can add new rows, delete existing ones, or modify values in existing rows. The DataSet tracks these changes.
  5. Update the Data Source: When ready to save changes, configure the DataAdapter's InsertCommand, UpdateCommand, and DeleteCommand. Then, call the Update() method of the DataAdapter, passing the DataSet. The DataAdapter will iterate through the modified rows in the DataSet and execute the appropriate SQL commands against the data source to synchronize the changes. The connection is opened and closed as needed during this process.

Advantages of Disconnected Data Access

Considerations

Concurrency Issues:

Since the connection is closed after data retrieval, applications need to handle potential concurrency issues. If multiple users are modifying the same data, conflicts can arise when updating. The DataAdapter.Update() method has mechanisms to handle row-by-row updates and can detect optimistic concurrency violations.

Managing State:

It's important to keep track of the state of data within the DataSet (e.g., whether a row is new, modified, or deleted) to ensure that the correct update commands are generated.

Example Snippet (Conceptual C#)


using System.Data;
using System.Data.SqlClient;

// ...

string connectionString = "Your_Connection_String_Here";
string selectSql = "SELECT CustomerID, CompanyName FROM Customers";
string updateSql = "UPDATE Customers SET CompanyName = @CompanyName WHERE CustomerID = @CustomerID";

using (SqlConnection connection = new SqlConnection(connectionString))
{
    DataSet dataSet = new DataSet();
    SqlDataAdapter dataAdapter = new SqlDataAdapter(selectSql, connection);

    // Configure the UPDATE command for the SqlDataAdapter
    SqlCommand updateCommand = new SqlCommand(updateSql, connection);
    updateCommand.Parameters.Add("@CompanyName", SqlDbType.NVarChar, 40, "CompanyName");
    updateCommand.Parameters.Add("@CustomerID", SqlDbType.NVarChar, 5, "CustomerID");
    dataAdapter.UpdateCommand = updateCommand;

    // Populate the DataSet
    dataAdapter.Fill(dataSet, "Customers");

    // --- Modify data in the DataSet ---
    DataTable customersTable = dataSet.Tables["Customers"];
    DataRow firstRow = customersTable.Rows[0];
    firstRow["CompanyName"] = "Updated Company Name";
    customersTable.Rows.Add(new object[] {"NEWID", "New Company"}); // Example of adding a new row

    // --- Update the database ---
    // The connection will be opened and closed by the Update() method.
    dataAdapter.Update(dataSet, "Customers");
}
            

This example demonstrates the basic flow of populating a DataSet, modifying data, and then updating the data source using a SqlDataAdapter. Remember to configure the appropriate commands and handle potential errors.