ADO.NET — Connected & Disconnected Data Access
What it is & where it is used
ADO.NET is the low-level data access API in .NET (System.Data). Every ORM — Entity Framework, Dapper — is built on it. Interviews ask about it because it shows you understand what happens between your code and the database.
Two architectures:
- Connected —
DbConnection+DbCommand+DbDataReader: open a connection, stream rows forward-only, close. Fast, low memory. - Disconnected —
DataAdapterfills an in-memoryDataSet/DataTable; the connection is closed while you work; changes are pushed back withUpdate().
Providers: Microsoft.Data.SqlClient (SQL Server — the current, recommended package; System.Data.SqlClient is deprecated), Npgsql (PostgreSQL), MySqlConnector, Oracle.ManagedDataAccess.Core, Microsoft.Data.Sqlite.
Dapper (Stack Overflow, 2011) is a micro-ORM: extension methods on IDbConnection that map query results to objects, keeping SQL fully in your control with near-ADO.NET speed.
Versions & history
| Year | Milestone |
|---|---|
| 2002 | ADO.NET 1.0 with .NET Framework 1.0 (successor of COM-based ADO) |
| 2005 | ADO.NET 2.0: provider factories (DbProviderFactory), SqlBulkCopy, MARS, async-ish APIs |
| 2008 | .NET 3.5: LINQ to SQL, LINQ to DataSet; EF 1.0 (SP1) |
| 2012 | .NET 4.5: real async (OpenAsync, ExecuteReaderAsync) |
| 2011 | Dapper released by Stack Overflow |
| 2019 | Microsoft.Data.SqlClient 1.0 — new SQL Server driver shipped via NuGet |
| 2022–2025 | Microsoft.Data.SqlClient 5.x/6.x: TDS 8 / strict encryption, Encrypt=true by default (4.0+), Entra ID (Azure AD) authentication, SqlBatch (.NET 6 DbBatch) |
Breaking-change gotcha: Microsoft.Data.SqlClient 4.0+ defaults to
Encrypt=True. Local dev servers with self-signed certificates needTrustServerCertificate=True(dev only).
Lifecycle
Connected access lifecycle:
- Create
SqlConnectionwith a connection string. Open()/OpenAsync()— gets a physical connection from the pool (or creates one).- Create
SqlCommand(SQL text or stored procedure) + parameters. - Execute:
ExecuteReader(rows),ExecuteScalar(single value),ExecuteNonQuery(rows affected). - Read with
SqlDataReader.Read()forward-only, column by column. - Close/Dispose reader → command → connection (with
using) — the connection returns to the pool, not physically closed.
Disconnected lifecycle: SqlDataAdapter.Fill(dataSet) (opens and closes the connection automatically) → work offline (edit rows; each DataRow has a RowState: Added, Modified, Deleted, Unchanged) → adapter.Update(dataSet) generates INSERT/UPDATE/DELETE (via SqlCommandBuilder or explicit commands) → AcceptChanges().
Transaction lifecycle: BeginTransaction() → assign to every command → execute → Commit() or Rollback() (automatic rollback on dispose without commit).
Tools used to develop
- SQL Server Management Studio (SSMS) / Azure Data Studio (retiring Feb 2026 in favour of the VS Code MSSQL extension) — write and test SQL.
- SQL Server Profiler / Extended Events — see what your app sends.
- Visual Studio Server Explorer / SQL Server Object Explorer.
- Dapper, Dapper.Contrib, DbUp (migrations as SQL scripts), RepoDB.
- Testcontainers for .NET — real SQL Server in Docker for tests.
- Polly — retry transient SQL errors (or
SqlRetryLogicProviderin SqlClient 3.0+).