fhg
Volume 10, Number 24 -- June 30, 2010

Generic Database Access with .NET 2.0

Published: June 30, 2010

by Michael Sansoterra

A difficult task for developers is to foresee how an application may evolve in the future. As we all know, sometimes the unrealistic becomes reality. Say you have an application that will start on SQL Server and possibly later be moved to DB2 for i or vice versa. How do you create a data-centric application in .NET that isn't tied to a particular database server? The answer lies in writing "database-agnostic" code.

Let's back up for a moment to when .NET was in its infancy. When .NET was first released, each ADO.NET database provider had its own set of classes. If you wanted to program against an Oracle database, you'd have to use the Oracle specific classes. Likewise, if you wanted to program against DB2 or SQL Server, you'd need to use the classes designed specifically for accessing those databases. Of course you could access any number of databases using the .NET ODBC or OLE DB wrapper classes, but these providers have overhead issues of their own as they rely on the older Microsoft COM technology.

Further, when a database vendor creates a .NET-managed provider to access its database engine, the vendor has to write a specific set of classes for implementing the following general functionality:

  • Connection--used to establish a connection to a database
  • Command--to provide methods for executing stored procedures, DDL, and DML SQL statements
  • DataReader--a lightweight class for reading through rows in a read only/forward only fashion
  • DataAdapter--a class for interacting with the database for data retrieval and data modifications
  • Transactions--provides the ability to implement transaction based processing
  • Parameter--allows developers to specify parameter attributes and values when executing a parameterized SQL statement
  • Exceptions--a set of classes that represent various errors that can occur such as invalid parameters, unable to connect, etc.
  • Data Types--a set of classes that correspond to each of the database server's data types

In Table 1, the connection, command, data reader, and data adapter class names are shown for four popular database providers:


DB2 for i

SQL Server

Oracle

ODBC

iDB2Connection

SqlConnection

OracleConnection

OdbcConnection

iDB2Command

SqlCommand

OracleCommand

OdbcCommand

iDB2DataReader

SqlDataReader

OracleDataReader

OdbcDataReader

iDB2DataAdapter

SqlDataAdapter

OracleDataAdapter

OdbcDataAdapter

Table 1--Selected class names used for four popular database providers.


Starting in .NET 2.0, Microsoft added a set of generic database provider classes intended to allow developers to access any database. Click here for a quick introduction to this "factory design pattern," which essentially allows access to multiple database providers using a single API.

If you're familiar with Java Database Connectivity (JDBC), this concept is very similar to the JDBC API where a database specific provider is loaded and thereafter all database access is subsequently accomplished through a single programming interface (provided by the java.sql package).

Prior to .NET 2.0, an application that needed to interact with multiple databases would have to conditionally instantiate objects from the various provider classes (or use a generic provider such as ODBC). However, a .NET 2.0 compatible provider is required to implement certain framework interfaces such as IDbConnection, IDbCommand, IDataReader, IDataAdapter, etc. So when a database vendor creates a .NET 2.0 data provider that implements these interfaces, the provider functionality can also be accessed through a single set of generic classes in the System.Data.Common namespace. Here are four of the generic database classes:

  • DbConnection
  • DbCommand
  • DbDataReader
  • DbDataAdapter

Let's look at a simple example. Whereas an application designed for use with the DB2 for i provider might be coded using IBM's specific classes like this (examples are C#):

public DataTable GetSalesOrderDetail(string ConnectionString, int OrderId)
{
//
// Open a connection using the DB2 for i managed provider
//
iDB2Connection conn = new iDB2Connection(ConnectionString);
 conn.Open();
 //
 // SQL: Retrieve sales order detail for requested order id
 //
 iDB2Command cmd = conn.CreateCommand();
 cmd.CommandText = "Select * From SalesOrderDetail Where 
 SalesOrderId="+OrderId;
 //
 // Get the results in a DataReader and load into a DataTable
 //
 iDB2DataReader dr = cmd.ExecuteReader(CommandBehavior.CloseConnection);
 DataTable dt = new DataTable("SalesOrderDetail");
 dt.Load(dr);
 return dt;
 }

Using .NET 2.0, it can be coded like this to accept multiple database providers:

 public DataTable GetSalesOrderDetail(string ProviderName, 
 string ConnectionString, int OrderId)
 {
 //
 // Load provider by name
 //
 DbProviderFactory db = DbProviderFactories.GetFactory(ProviderName);
 //
 // Open a connection using the provider's connection string
 //
 DbConnection conn = db.CreateConnection();
 conn.ConnectionString = ConnectionString;
 conn.Open();
 //
 // SQL: Retrieve sales order detail for requested order id
 //
 DbCommand cmd = conn.CreateCommand();
 cmd.CommandText = "Select * From SalesOrderDetail Where 
 SalesOrderId="+OrderId;
 //
 // Get the results in a DataReader and load into a DataTable
 //
 DbDataReader dr = cmd.ExecuteReader(CommandBehavior.CloseConnection);
 DataTable dt = new DataTable("SalesOrderDetail");
 dt.Load(dr);
 return dt;
 }

When comparing the code, both examples are almost identical except the first uses provider specific classes and the latter uses the generic classes. The DbProviderFactories class is the key to generic database programming, as it contains a collection of .NET 2.0 managed providers installed on the machine. You retrieve your specific installed provider by passing it with what is referred to as the "invariant provider name." (See samples below.) For those familiar with Java, this is similar to loading a JDBC driver using the Class.forName method.

Although this example is simplistic, it's easy to understand how the same code can service many different databases by soft-coding the provider information and connection string. This information can easily be soft-coded by storing it in an app.config or web.config file.

If, for example, you're using the IBM DB2 for i provider with the generic classes, the IBM specific classes are still used under the covers but access is done via a generic, single API. In fact, assuming other databases in your company had identical schema and table info, the sample method GetSalesOrderDetail could run equally well against, Oracle, ODBC-based, SQL Server, or DB2 for i database servers as shown here:

DataTable dtSalesOrderDetail;

// NOTE: 15234 is the order number to retrieve

// Oracle Provider
dtSalesOrderDetail=GetSalesOrderDetail(
"System.Data.OracleClient", 
"Data Source=localhost;User ID=MyUser;Password=MyPassword;
Unicode=True",15234);

// ODBC Driver (IBM DB2 for i connection string)
dtSalesOrderDetail=GetSalesOrderDetail(
"System.Data.Odbc",
"DSN=AS400;System=db2.mycompany.com;uid=MyUser;pwd=MyPassword;
nam=0;DBQ=ADVWORKS,*USRLIBL;" ,15234);

// SQL Server Provider
dtSalesOrderDetail=GetSalesOrderDetail(
"System.Data.SqlClient",
"Data Source=localhost;Initial Catalog=AdventureWorks;Integrated 
Security=SSPI;" ,15234);

// IBM DB2 UDB for iSeries .NET Managed Provider
dtSalesOrderDetail=GetSalesOrderDetail(
"IBM.Data.DB2.iSeries",
"DataSource=iSeries.mycompany.local;UserID=MyUser;Password=
MyPassword;Naming=System;LibraryList=,*USRLIBL;DefaultCollection=
ADVWORKS;" ,15234);

While it's great to be able to access multiple databases with one set of code, a few obvious hindrances to this programming model are:

  • Provider specific functionality may not be accessible from the generic API
  • Not all database providers will implement all the functionality offered by the generic API
  • SQL statements may not use database specific SQL features (unless you put database specific forks in your code)

In the cases where database specific functionality is required that is not offered by the generic API, the generic data provider name can be cast back to its underlying data type. For example, to retrieve the DB2 for i provider specific ClientProgramID property from the iDB2Connection object, you could code to access the provider specific property as follows:

//
// Open a connection using the provider's connection string
//
DbConnection conn = db.CreateConnection();
conn.ConnectionString = ConnectionString;
conn.Open();
//
// Do something DB2 specific
//
if (conn is iDB2Connection)
{
Console.WriteLine(
(conn as iDB2Connection).ClientProgramID);
}

Finally, if you're using the DB2 for i provider in your application, make sure you have System i Access V6R1 or higher installed. Prior versions of the DB2 for i .NET managed provider are not .NET 2.0 compatible.

All in all, making your application "database-agnostic" will allow the application greater ability to service multiple database servers, or make a database specific application easier to migrate to another database platform if and when the time is right.


Michael Sansoterra is a DBA for Broadway Systems in Grand Rapids, Michigan. Send your questions or comments for Mike via the IT Jungle Contact page.




                     Post this story to del.icio.us
               Post this story to Digg
    Post this story to Slashdot


Sponsored By
SEQUEL SOFTWARE

SEQUEL ViewPoint®--Data Access & Analysis
for Power Systems™ Servers

                                               · Easy to use by IT and end users
                                               · Real-time data access and analysis
                                               · Queries, reports, pivot tables, drill-down analysis, kpi dashboards
                                               · IBM i-centric with multiplatform data access
                                               · Expert support and training
                                               · Secure data access
                                               · GUI, Web & green screen interface

SEQUEL--Fast, efficient & cost-effective data analysis

Click here for a FREE Information Kit!


Senior Technical Editor: Ted Holt
Technical Editor: Joe Hertvik
Contributing Technical Editors: Erwin Earley, Brian Kelly, Michael Sansoterra
Publisher and Advertising Director: Jenny Thomas
Advertising Sales Representative: Kim Reed
Contact the Editors: To contact anyone on the IT Jungle Team
Go to our contacts page and send us a message.

Sponsored Links

ManageEngine:  Who says iSeries systems monitoring software has to be expensive?
IBS:  Free e-book: The Six Margin Killers in Wholesale Distribution
COMMON:  Join us at the Fall 2010 Conference & Expo, Oct. 4 - 6, in San Antonio, Texas


 

IT Jungle Store Top Book Picks

Easy Steps to Internet Programming for AS/400, iSeries, and System i: List Price, $49.95
The iSeries Express Web Implementer's Guide: List Price, $49.95
The System i RPG & RPG IV Tutorial and Lab Exercises: List Price, $59.95
The System i Pocket RPG & RPG IV Guide: List Price, $69.95
The iSeries Pocket Database Guide: List Price, $59.00
The iSeries Pocket SQL Guide: List Price, $59.00
The iSeries Pocket Query Guide: List Price, $49.00
The iSeries Pocket WebFacing Primer: List Price, $39.00
Migrating to WebSphere Express for iSeries: List Price, $49.00
Getting Started With WebSphere Development Studio Client for iSeries: List Price, $89.00
Getting Started with WebSphere Express for iSeries: List Price, $49.00
Can the AS/400 Survive IBM?: List Price, $49.00
Chip Wars: List Price, $29.95


 
The Four Hundred
Top Concerns Survey Is Ready for IBM Eyes

Infor Commits Itself to Microsoft and Windows Technologies

Developing for IBM i: Why Does It Need To Be So Hard?

Mad Dog 21/21: Microclients: Thin Enough? Rich Enough?

IBM Tweaks More Rebate Deals to Cut Power7 Prices

Four Hundred Stuff
IdF, Logic Trends Fill a Gap in Microsoft Identity Software

ADC Austin Updates AJAX Generator for CA Plex

ASD Unveils BI Solution for Insurance Companies

nuBridges' Token Manager Gets Enterprise Upgrade

SafeData Gets Bought by Data Storage

Four Hundred Monitor
Four Hundred Monitor's
Full iSeries Events Calendar

System i PTF Guide
May 29, 2010: Volume 12, Number 22

May 22, 2010: Volume 12, Number 21

May 15, 2010: Volume 12, Number 20

May 8, 2010: Volume 12, Number 19

May 1, 2010: Volume 12, Number 18

April 24, 2010: Volume 12, Number 17

TPM at The Register
Oracle refreshes Sun Xeon server lineup

CPU, GPU makers gussie up their wares for Hot Chips

Azul goes virtual with Java appliance

Nimbula puffs up 'cloud operating system'

Oracle uses Sun as springboard in Q4

Neon to take mainframe complaints to Europe

Red Hat turns the crank of KVM enterprise virt

IBM sued over failed virtual PC server projects

AMD muscles Nvidia with fanless GPU coprocessors

AMD's Opteron 4100s march into x64 price war

Red Hat revenues swell to $209.1m

Tilera to stuff 200 cores onto single chip

THIS ISSUE SPONSORED BY:

SEQUEL Software
ProData Computer Services
WorksRight Software


Printer Friendly Version


TABLE OF CONTENTS
Generic Database Access with .NET 2.0

Spaces, Braces, and Semicolons

Admin Alert: High Availability Eliminates Disaster Recovery. . . Right?

Four Hundred Guru

BACK ISSUES




 
Subscription Information:
You can unsubscribe, change your email address, or sign up for any of IT Jungle's free e-newsletters through our Web site at http://www.itjungle.com/sub/subscribe.html.

Copyright © 1996-2010 Guild Companies, Inc. All Rights Reserved.
Guild Companies, Inc., 50 Park Terrace East, Suite 8F, New York, NY 10034

Privacy Statement