A Tale of Two Providers

The very first thing that every developer should know about ADO.NET is that it has a split personality. ADO.NET database accesses go through software modules known as data providers. Version 1.0 of the .NET Framework ships with two data providers:

OLE DB is a data access technology that originated in the heyday of COM. OLE DB providers layer a uniform object-oriented API over disparate databases, just as Open Database Connectivity (ODBC) drivers provide a procedural front end to different kinds of databases. OLE DB providers are available for a variety of non鈥揝QL Server databases. The .NET Framework鈥檚 OLE DB .NET provider lets you leverage existing OLE DB providers by calling out to them from managed code. Microsoft has tested the following OLE DB providers and deemed them compatible with the framework鈥檚 OLE DB .NET provider:

In the past, some developers used the MSDASQL OLE DB provider to access databases using ODBC. MSDASQL was a generic solution that permitted databases without an OLE DB provider of their own but that had ODBC drivers available to be accessed using the OLE DB API. MSDASQL is not compatible with the .NET Framework, but you can download an ODBC .NET provider that is compatible with the framework from Microsoft鈥檚 Web site.

So what does all this mean for the developer? For starters, you should decide on a provider before you write the first line of code in a project that relies on a database. Here are your choices:

If the database is neither Oracle nor Jet but an OLE DB provider is available for it, the provider might work. Then again, it might not. It depends on whether the database鈥檚 unmanaged OLE DB provider is compatible with the .NET Framework鈥檚 managed OLE DB .NET provider. Not all are. If the OLE DB driver isn鈥檛 compatible with the .NET Framework (or if it doesn鈥檛 exist), but an ODBC driver is available for the database in question, download Microsoft鈥檚 ODBC .NET driver and use it to talk to the database.

The System.Data.SqlClient and System.Data.OleDb Namespaces

Your choice of provider directly impacts the code that you write. Some ADO.NET classes work with all providers. DataSet is a good example. Defined in the System.Data namespace, DataSet works equally well with SQL Server .NET and OLE DB .NET. But many ADO.NET classes target a specific provider. For example, DataAdapter comes in two flavors: SqlDataAdapter for the SQL Server .NET provider and OleDbDataAdapter for the OLE DB .NET provider. Sql颅DataAdapter and other SQL Server .NET classes belong to the System.Data.SqlClient namespace. OleDbDataAdapter is defined in System.Data.OleDb.

How does this affect the code that you write? Here鈥檚 a short sample that uses the SQL Server .NET provider to list all the book titles contained in the 鈥淭itles鈥?table of the Pubs database that comes with SQL Server:

using聽System.Data.SqlClient;
聽聽.
聽聽.
聽聽.
SqlConnection聽conn聽=聽new聽SqlConnection
聽聽聽聽("server=localhost;database=pubs;uid=sa;pwd=");
try聽{
聽聽聽聽conn.Open聽();
聽聽聽聽SqlCommand聽cmd聽=聽new聽SqlCommand聽("select聽*聽from聽titles",聽conn);
聽聽聽聽SqlDataReader聽reader聽=聽cmd.ExecuteReader聽();
聽聽聽聽while聽(reader.Read聽())
聽聽聽聽聽聽聽聽Console.WriteLine聽(reader["title"]);
}
catch聽(SqlException聽ex)聽{
聽聽聽聽Console.WriteLine聽(ex.Message);
}
finally聽{
聽聽聽聽conn.Close聽();
}

And here鈥檚 the equivalent code rewritten to use the OLE DB .NET provider (via the unmanaged OLE DB provider for SQL Server). Changes are highlighted in bold:

using聽System.Data.OleDb;
聽聽.
聽聽.
聽聽.
OleDbConnection聽conn聽=聽new聽OleDbConnection
聽聽聽聽("provider=sqloledb;server=localhost;database=pubs;uid=sa;pwd=");

try聽{
聽聽聽聽conn.Open聽();
聽聽聽聽OleDbCommand聽cmd聽=
聽聽聽聽聽聽聽聽new聽OleDbCommand聽("select聽*聽from聽titles",聽conn);
聽聽聽聽OleDbDataReader聽reader聽=聽cmd.ExecuteReader聽();
聽聽聽聽while聽(reader.Read聽())
聽聽聽聽聽聽聽聽Console.WriteLine聽(reader["title"]);
}
catch聽(OleDbException聽ex)聽{
聽聽聽聽Console.WriteLine聽(ex.Message);
}
finally聽{
聽聽聽聽conn.Close聽();
}

Notice that SqlConnection, SqlCommand, SqlDataReader, and SqlException became OleDbConnection, OleDbCommand, OleDbDataReader, and OleDbException, and that the database connection string changed too. ADO.NET provides a common API for various types of databases, but the details of that API differ slightly depending on the managed provider that you choose.

The good news is that other than class names and connection strings, few differences distinguish the SQL Server .NET and OLE DB .NET providers. The SqlDataAdapter and OleDbDataAdapter classes, for example, implement the same set of methods, properties, and events. Converting SqlDataAdapter code to use OleDbDataAdapter instead is mostly a matter of using find-and-replace to change the class names. That鈥檚 good to know if you originally design your software around a SQL Server database and later decide to switch to Oracle (or vice versa).

In general, I鈥檒l use the Sql classes for the code samples in this chapter. Unless I say otherwise, you can assume that changing Sql to OleDb in the class names is sufficient to switch providers. Provider-specific class names without Sql or OleDb prefixes refer generically to classes of both types. For example, when I use the term DataReader, I鈥檓 referring to both SqlDataReader and OleDbDataReader.