Data Access in ADO.NET

By: Cary Jensen

Abstract: ADO.NET provides the native data access layer for the .NET framework. This article is the first in a series to look at ADO.NET, and begins a discussion of the data access mechanism.

Up until recently, nearly all data access in Borland's RAD products was supplied by the Borland Database Engine. Beginning with Delphi 3, additional data access mechanisms, including ClientDataSet and DataSnap (originally known as MIDAS) were added. As of Delphi 7, Delphi natively supports no less than 6 distinct data access mechanisms (not counting third-party solutions). The most recent of these, and arguably most important for developers as .NET continues to evolve, is the support for ADO.NET provided by Borland's new .NET development tools, including C# Builder and the Delphi for .NET preview compiler.

This article is designed to provide you with an overview of ADO.NET's data access mechanism, as it is defined in the .NET 1.1 Framework. The next article in this series will continue this discussion with a detailed look at the data storage classes, including the DataSet class.

Throughout this series there are a couple of points that you should keep in mind. First, these articles, and the accompanying code (when appropriate), are based on the Delphi 7 preview compiler (update version 3, first made available in Spring 2003). At the time of this writing, Borland does not yet have an integrated development environment (IDE) for Delphi for .NET. Consequently, the example projects were not built using visual design tools. Instead, all visual components (when a project calls for them) were created and configured entirely in code.

The second point is that Borland developers may not end up using ADO.NET using the specific techniques described in this series. It is likely that Borland will provide some sort of .NET ClientDataSet that will greatly simplify your use of data in managed assemblies, just as the VCL's ADODataSet classes simplify the use of ADO (activeX data object). However, if Borland develops this .NET ClientDataSet using an approach similar to its ADODataSet classes, it is likely that you will have the option of using both the ClientDataSet interface, as well as the more low-level techniques described in this series.

ADO.NET: Data Access and Data Storage

ADO.NET is the name for the data layer provided by the .NET framework class library (FCL). Conceptually, ADO.NET can be divided into two distinct parts: the data access mechanism and the data storage system.

All of the principle classes, interfaces, and types used in ADO.NET are defined under the System.Data second-level namespace. The classes associated with the data storage system are standalone classes that you can employ in any ADO.NET application. These classes include DataColumn, DataRelation, DataRow, DataSet, and DataTable. Of these, the most important is the DataSet class.

Unlike the storage mechanism, which is defined around classes, the data access mechanism is defined around interfaces. These interfaces are implemented by concrete classes associated with a particular data access mechanism. In the .Net Framework version 1.1 there are five data access mechanisms. These are associated with the System.Data.SqlClient, System.Data.OleDb, System.Data.Odbc, System.Data.SqlServerCE and System.Data.OracleClient third-level namespaces. 

Consider the SqlDataAdapter class in the System.Data.SqlClient namespace, for example. This class, which is sometimes generically called a DataAdapter, is used to load data into a DataSet. SqlDataAdapter, like all other DataAdapters, implements the IDbDataAdapter interface. Other IDbDataAdapter implementing classes include OleDbDataAdapter, OdbcDataAdapter, and OracleDataAdapter.

It is worth noting that many database vendors have developed, or are in the process of developing, their own specific data access mechanisms. As a result, even though one of the 1.1 framework data access mechanisms will probably provide you with access to these databases, the vendor supplied data access classes are likely to be optimized for the particular server.

ADO.NET Data Access Interfaces

The following diagram depicts the data access layer in the ADO.NET framework, and its relationship to the DataSet class. As you can see here, the classes that implement the data access interfaces are designed to cooperate in accessing data from an underlying database, with the IDbDataAdapter implementing class being used to fill a DataSet instance with this acquired data.

That data access in the .NET framework is designed around interfaces is significant, in that it provides for the API of data access while leaving the specific details to the implementing classes. In the .NET framework 1.1, each of these interfaces are implemented by a class in one of the data access mechanism-specific namespaces. For example, if you are going to access data using SQL server, you can use the SqlConnection, SqlCommand, SqlDataReader, and SqlDataAdapters classes. On the other hand, if you want to access data using an OleDb provider, you can use the corresponding classes from the System.Data.OleDb namespace, which are OleDbConnection, OleDbCommand, OleDbDataReader, and OleDbDataAdapter classes, respectively.

The following sections describe the common data access interfaces in the preceding figure. For the benefit of current Borland RAD developers, the similarity between each of these interfaces and their VCL equivalent is discussed.

IDbConnection

Classes that implement the IDbConnection interface are used to establish a connection to a data source. In most cases, this will be a database associated with a particular database server. However, since both OleDB and ODBC are supported, it is possible to connect to any data source for which there are OleDb provider or ODBC (open database connectivity) drivers, such as Paradox, dBase, and MS Access.

Classes that implement the other interfaces listed in the preceding diagram all rely on the connection supplied by an IDbConnection implementing class. However, if you are using a DataSet that does not load or resolve its data to an underlying database (such as a DataSet that obtains its data from an XML file), you do not need to use a class that implements the IDbConnection interface.

Each IDbConnection implementing class has one or more constructors that are used to establish the connection to the data source. This interface also provides for control over database transactions.

The IDbConnection interface defines features that are similar to those provided by the SQLConnection component of dbExpress, ADOConnection of ADO, or the TSession component of the BDE.

IDbCommand

Classes that implement the IDbCommand interface are used to define and execute queries against the underlying database. A class that implements the IDbCommand interface must be associated with a class that implements the IDbConnection interface. 

IDbCommand queries may include parameters. When they do, you bind data to individual parameters using a class that implements the IDbDataParameter interface. All parameters associated with an IDbCommand implementing class are found in the Parameters property of the implementing class. This property is an instance of a class that implements IDataParameterCollection.

Classes that implement the IDbCommand interface are similar to the VCL's ADOCommand component.

IDataReader

Classes that implement the IDataReader class provide a fast, forward-only cursor to the result set returned by an IDbCommand instance. Classes that implement this interface are used to perform operations that do not require the caching of the data. For example, operations where you do not need to load the data into a DataTable, or operations that iterate through a result set, performing a conditional calculation on each record encountered. Classes that implement the IDataReader interface are similar to the SQLDataSet class in dbExpress. 

IDbDataAdapter

You use a class that implements the IDbDataAdapter interface to read data and subsequently load it into a DataSet. Classes that implement the IDbDataAdapter interface must point to an IDbConnection implementing class in order to access the data. In addition to loading data into a DataSet, IDbDataAdapters define the queries that are used to load data from, and save data to, an underlying database. In many ways, IDbDataAdapter implementing objects are similar to Delphi's DataSetProvider classes.

IDbDataAdapter implementing classes require at least one SQL statement, and in many cases as many as four. At a minimum, an IDbDataAdapter implementing class requires a SQL SELECT statement to identify which records to load. If the data accessed by an IDbDataAdapter implementing class can be modified, inserted, or deleted, corresponding SQL statements that specify how this data is to be updated, inserted, and deleted are also required.

An IDbDataAdapter's SQL statements are associated with the SelelectCommand, InsertCommand, UpdateCommand, and DeleteCommand properties of the IDbDataAdapter implementer, which are instances of classes that implement IDbCommand. All of the IDbDataAdapter implementing classes can take a SQL SELECT statement as a parameter of at least one of their overloaded constructors. When one of these constructors is used to create the IDbDataAdapter instance, it is not necessary to explicitly assign an IDbCommand implementing class to the SelectCommand property.

Instead of explicitly assigning SQL statements to the InsertCommand, UpdateCommand, and DeleteCommand properties, you can use an appropriate command builder class to generate the associated SQL commands. Examples of these classes include the SQLCommandBuilder and OleDbCommandBuilder classes.

In the next article in this series I will take a look at the classes that participate in the storage of data.

About the Author

Cary Jensen is President of Jensen Data Systems, Inc., a Texas-based training and consulting company that won the 2002 and 2003 Delphi Informant Magazine Readers Choice awards for Best Training. He is the author and presenter for Delphi Developer Days (www.DelphiDeveloperDays.com), an information-packed Delphi (TM) seminar series that tours North America and Europe, and Delphi Developer Days Power Workshops, focused Delphi (TM) training. Cary is also an award-winning, best-selling co-author of eighteen books, including Building Kylix Applications (2001, Osborne/McGraw-Hill), Oracle JDeveloper (1999, Oracle Press), JBuilder Essentials (1998, Osborne/McGraw-Hill), and Delphi In Depth (1996, Osborne/McGraw-Hill). For information about onsite training and consulting you can contact Cary at cjensen@jensendatasystems.com, or visit his Web site at www.JensenDataSystems.com.

New!: Stay informed, stay in touch. Register online to receive the free Developer Days ELetter: information, observations, and events for the Delphi and .NET developer by Cary Jensen. Each Developer Days ELetter includes Delphi tips and tricks, .NET information, links to recent articles posted to the Borland Developers Network site, and events in the Delphi community. Visit www.DeveloperDays.com.

Copyright ) 2003 Cary Jensen, Jensen Data Systems, Inc.
ALL RIGHTS RESERVED. NO PART OF THIS DOCUMENT CAN BE COPIED IN ANY FORM WITHOUT THE EXPRESS, WRITTEN CONSENT OF THE AUTHOR.


Server Response from: ETNASC04