C# ADO.NET ODBC Tutorial

Use the ODBC .NET Data Provider to access data from your C sharp ADO.NET applications.

Contents

What is .NET?

Microsoft describe .NET in the following way:

".NET is the Microsoft Web services strategy to connect information, people, systems, and devices through software. Integrated across the Microsoft platform, .NET technology provides the ability to quickly build, deploy, manage, and use connected, security-enhanced solutions with Web services. .NET-connected solutions enable businesses to integrate their systems more rapidly and in a more agile manner and help them realize the promise of information anytime, anywhere, on any device."

For more details about the entire framework, consult the FAQ Microsoft provide at:

http://msdn.microsoft.com/en-us/library/ms973850.aspx

.NET and Data Access

ADO.NET is the data access model for .NET-based applications. This interface will be familiar to users of the older ActiveX Data Objects (ADO) data access interface. However, there are some important differences between the two.

A useful Microsoft document that details ADO.NET from an ADO programmer’s perspective can be found at:

http://msdn.microsoft.com/en-us/library/ms973217.aspx

One of the key changes that ADO.NET introduces is the replacement of the ADO Recordset object with a combination of the DataTable, DataSet, DataAdapter, and DataReader objects. A DataTable represents a collection of rows from a single table, and in this respect is similar to the Recordset. A DataSet represents a collection of DataTable objects, together with the relationships and constraints that bind the various tables together.

One of the key characteristics of the DataSet is that it has no knowledge of the underlying data source that might have been used to populate it. The actual interface to the underlying data source is provided by using one of a number of .NET Data Providers. A .NET Data Provider comprise four key objects (Connection, Command, DataReader and DataAdapter).

.NET Data Providers fall into two categories: bridge providers and native providers. Bridge providers, such as those supplied for OLE DB and ODBC, allow you to use data libraries designed for earlier data access technologies. Native providers are normally provided by the actual database supplier and provide interfaces to specific databases. For example, SQL Server has a native provider available from Microsoft.

What Does This Document Show?

This document concentrates on the use of the ODBC .NET Data Provider to provide access to data though the use of ODBC drivers, which are available for most database systems. The remainder of this document will use Easysoft ODBC-ISAM Driver as the sample ODBC driver, this provides connection via Easysoft ODBC-ODBC Bridge to data stored in ISAM files. The examples are equally appropriate when using the ODBC-ODBC Bridge, the Easysoft ODBC-Oracle Driver, the Easysoft ODBC-InterBase Driver, the Easysoft ODBC-RMS Driver or any other Windows ODBC driver.

What Do You Need to Recreate These Examples?

The Easysoft software needed to recreate the following examples can be downloaded from the Easysoft web site. All the Microsoft .NET tools are available from Microsoft.

The Sample ODBC Data Source

In this document we will use the sample data provided by installing the Easysoft ODBC-ISAM Driver on the target machine, and the Easysoft ODBC-ODBC Bridge Client on the local Windows machine.

A Simple Example

The following steps will create a application that show the basic operations used to interface ODBC and .NET.

  1. Create a new Visual Studio Project. For this example, we will use a C# Console Application.
  2. Import the System.data.Odbc namespace into the application, to allow us to use the ODBC .NET Data Provider:
    using System.Data.Odbc;
  3. Now create an OdbcConnection object and connect it to our sample data source.
    OdbcConnection DbConnection = new OdbcConnection("DSN=SAMPLE_ISAM");

    This example uses a DSN connection, but a DSN free connection can be used by using the DRIVER={} format. Consult your ODBC driver documentation for more details.

  4. Now open that OdbcConnection object:
    DbConnection.Open();
  5. Now using the OdbcConnection, we will create an OdbcCommand:
    OdbcCommand DbCommand = DbConnection.CreateCommand();
  6. Using that command, we can issue a Query and create an OdbcDataReader:
    DbCommand.CommandText = "SELECT * FROM NATION";
    OdbcDataReader DbReader = DbCommand.ExecuteReader();
  7. Now we have an OdbcDataReader, we can find the number and names of the columns in the result set, and display this on the console.
    int fCount = DbReader.FieldCount;
    Console.Write(":");
    for ( int i = 0; i < fCount; i ++ )
    {
           String fName = DbReader.GetName(i);
           Console.Write( fName + ":");
    }
    Console.WriteLine();
  8. Now we can read each row from the result set, and read each column in that row and display its value.
    while( DbReader.Read()) 
    {
             Console.Write( ":" );
             for (int i = 0; i < fCount; i++)
             {
                     String col = DbReader.GetString(i);
                            
                     Console.Write(col + ":");
             }
             Console.WriteLine();
     }
  9. Once OdbcDataReader.Read() returns false, we have read every row in the result set, so now we should cleanup the objects we have used
    DbReader.Close();
    DbCommand.Dispose();
    DbConnection.Close();

We now have a complete C# ADO.NET application that connects to our ODBC data source, issues a query then displays the results from that query.

The complete program source for this section can be found in CSharpODBCExample1.cs

Getting Error Information

The sample program did not contain provision for dealing with errors. Unfortunately in the real world, we need to handle unexpected situations. So we will now add some extra code to our sample that allows us to handle errors.

First, we will allow the connection string to be passed in on the command line of the application.

if (args.Length != 1 )
{
    Console.WriteLine("usage: sample connection-string");
    return;
}
String connStr = args[0];

OdbcConnection DbConnection = new OdbcConnection( connStr );

Now we can set the command line properties to the same as before.

"DSN=SAMPLE_ISAM"

The program can be run as before. However, if the user enters an invalid connection string, the program will fail when the OdbcConnection.Open() method is called. The program will throw an Exception at this point, and we can change our code to catch this exception and display information from the ODBC system to the user.

The exception thrown will be an OdbcException, and we can use this to extract the error string that the ODBC Driver Manager has returned.

try
{
  DbConnection.Open();
}
catch (OdbcException ex)
{
  Console.WriteLine("connection to the DSN '" + connStr + "' failed.");
  Console.WriteLine("The OdbcConnection returned the following message");
  Console.WriteLine(ex.Message);
  return;
}

We will also allow the user to enter the query to executed and then set this string as the query to be executed:

Console.Write("SQL> ");
String query = Console.ReadLine();
OdbcCommand DbCommand = DbConnection.CreateCommand();
DbCommand.CommandText = query;

But now the SQL may not be valid, so the OdbcCommand.ExecuteReader() may also throw an exception, which we can catch and display.

try
{
  OdbcDataReader DbReader = DbCommand.ExecuteReader();
  // rest of the code to process the result set
}
catch (OdbcException ex)
{
  Console.WriteLine("Executing the query '" + query + "' failed."); 
  Console.WriteLine("The OdbcCommand returned the following message");
  Console.WriteLine(ex.Message);
  return;
}

The complete program source for this section can be found in CSharpODBCExample2.cs

Updating Data

Now that we can enter a query at the command line, our application must handle queries that do more than just create result sets. At the moment, if we try to create a new table using the application, the OdbcDataReader will be created with no columns, so we can use this do decide how to process the query.

int fCount = DbReader.FieldCount;
if (fCount > 0)
{
        // process result set
}
else 
{
        // process non result set
}

In the case of a non result set generating statement, we can use the OdbcDataReader.RecordsAffected property to see how many rows have been altered by an update/delete/insert statement.

else
{
        int row_count =  DbReader.RecordsAffected;
        Console.WriteLine( "Query affected " + row_count + " row(s)");
}

Our sample can now query and update the database.

The complete program source for this section can be found in CSharpODBCExample3.cs.

Multiple Results

Most databases can now process commands like this:

select * from table1; select * from table2

This will create more than one result set. So we will now add code to our example that allows each result set to be processed in turn. The OdbcDataReader object has a method NextResult() that will move the OdbcDataReader to the next result from the query. So all we need to do is wrap the query processing in a loop processing each result in turn until NextResult() returns false:

OdbcDataReader DbReader = DbCommand.ExecuteReader();
do
{
        // process result
}
while (DbReader.NextResult());

Our final program can be found in CSharpODBCExample4.cs.

Appendix A: Resources

Article Feedback

* Did this content help you?
* Please select one option based on your first choice:

(* Required Fields)