Chapter 20. Data access using ADO.NET

20.1. Introduction

Spring provides an abstraction for data access via ADO.NET that provides the following benefits and features

  • Consistent and comprehensive database provider interfaces for both .NET 1.1 and 2.0

  • Integration with Spring's transaction management features.

  • Template style use of DbCommand that removes the need to write typical ADO.NET boiler-plate code.

  • 'One-liner' implementations for the most common database usage patterns lets you focus on the 'meat' of your ADO.NET code.

  • Easy database parameter creation/management

  • Provider independent exceptions with database error codes and higher level DAO exception hierarchy.

  • Centralized resource management for connections, commands, data readers, etc.

  • Simple DataReader to Object mapping framework.

This chapter is divided up into a number of sections that describe the major areas of functionality within Spring's ADO.NET support.

  • Motivations - describes why one should consider using Spring's ADO.NET features as compared to using 'raw' ADO.NET API.

  • Provider Abstraction - a quick overview of Spring's provider abstraction.

  • Approaches to ADO.NET Data Access - Discusses the two styles of Spring's ADO.NET data access classes - template and object based.

  • Introduction to AdoTemplate - Introduction to the design and core methods of the central class in Spring's ADO.NET support.

  • Exception Translation - Describes the features of Spring's data access exceptions

  • Parameter Management - Convenience classes and methods for easy parameter management.

  • Mapping DBNull values - Strategy for providing centralized and transparent mapping of DBNull values to CLR types when accessing an IDataReader.

  • Basic data access operations - Usage of AdoTemplate for IDbCommand 'ExecuteScalar' and 'ExecuteNonScalar' functionality

  • Queries and Lightweight Object Mapping - Using AdoTemplate to map result sets into objects

  • DataSet and DataTable operations - Using AdoTemplate with DataSets and DataTables

  • Modeling ADO.NET operations as .NET objects - An object-oriented approach to data access operations.

20.2. Motivations

There are a variety of motivations to create a higher level ADO.NET persistence API.

Encapsulation of common 'boiler plate' tasks when coding directly against the ADO.NET API. For example here is a list of the tasks typically required to be coded for processing a result set query. Note that the code needed when using Spring's ADO.NET framework is in italics.

  1. Define connection parameters

  2. Open the connection

  3. Specify the command type and text

  4. Prepare and execute the statement

  5. Set up the loop to iterate through the results (if any)

  6. Do the work for each iteration

  7. Process any exception

  8. Display or rollback on warnings

  9. Handle transactions

  10. Close the connection

Spring takes care of the low-level tasks and lets you focus on specifying the SQL and doing the real work of extracting data. This standard boiler plate pattern is encapsulated in a class, AdoTemplate. The name 'Template' is used because if you look at the typical code workflow for the above listing, you would essentially like to 'template' it, that is stick in the code that is doing the real work in the midst of the resource, transaction, exception management.

Another very important motivation is to provide an easy means to group multiple ADO.NET operations within a single transaction while at the same time adhering to a DAO style design in which transactions are initiated outside the DAOs, typically in a business service layer. Using the 'raw' ADO.NET API to implement this design often results in explicitly passing around of a Transaction/Connection pair to DAO objects. This infrastructure task distracts from the main database task at hand and is frequently done in an ad-hoc manner. Integrating with Spring's transaction management features provides an elegant means to achieve this common design goal. There are many other benefits to integration with Spring's transaction management features, see Chapter 17, Transaction management for more information.

Provider Independent Code: In .NET 1.1 writing provider independent code was difficult for a variety of reasons. The most prominent was the lack of a lack of a central factory for creating interface based references to the core ADO.NET classes such as IDbConnection, IDbCommand, DbParameter etc. In addition, the APIs exposed by many of these interfaces were minimal or incomplete - making for tedious code that would otherwise be more easily developed with provider specific subclasses. Lastly, there was no common base class for data access exceptions across the providers. .NET 2.0 made many changes for the better in that regard across all these areas of concern - and Spring only plugs smaller holes in that regard to help in the portability of your data access code.

Resource Management: The 'using' block is the heart of elegant resource management in .NET from the API perspective. However, despite its elegance, writing 2-3 nested using statement for each data access method also starts to be tedious, which introduces the risk of forgetting to do the right thing all the time in terms of both direct coding and 'cut-n-paste' errors. Spring centralizes this resource management in one spot so you never forget or make a mistake and rely on it always being done correctly.

Parameter management: Frequently much of data access code is related to creating appropriate parameters. To alleviate this boiler plate code Spring provides a parameter 'builder' class that allows for succinct creation of parameter collections. Also, for the case of stored procedures, parameters can be derived from the database itself which reduces parameter creation code to just one line.

Frequently result set data is converted into objects. Spring provides a simple framework to organize that mapping task and allows you to reuse mapping artifacts across your application.

Exceptions: The standard course of action when an exception is thrown from ADO.NET code is to look up the error code and then re-run the application to set a break point where the exception occurred so as to see what the command text and data values were that caused the exception. Spring provides exceptions translation from these error codes (across database vendors) to a Data Access Object exception hierarchy. This allows you to quickly understand the category of the error that occurred and also the 'bad' data which lead to the exception.

Warnings: A common means to extract warning from the database, and to optionally treat those warnings as a reason to rollback is not directly supported with the new System.Data.Common API

Portability: Where possible, increase the portability of code across database provider in the higher level API. The need adding of a parameter prefix, i.e. @ for SqlServer or ':' for oracle is one such example of an area where a higher level API can offer some help in making your code more portable.

Note that Spring's ADO.NET framework is just 'slightly' above the raw API. It does not try to compete with other higher level persistence abstractions such as result set mappers (iBATIS.NET) or other ORM tools (NHibernate). (Apologies if your favorite is left out of that short list). As always, pick and choose the appropriate level of abstraction for the task at hand. As a side note, Spring does offer integration with higher level persistence abstractions (currently NHibernate) providing such features as integration with Spring's transaction management features as well as mixing orm/ operations within the same transaction.

20.3. Provider Abstraction

Before you get started executing queries against the database you need to connect to it. Chapter 19, DbProvider covers this topic in detail so we only discuss the basic idea of how to interact with the database in this section. One important ingredient that increases the portability of writing ADO.NET applications is to refer to the base ADO.NET interfaces, such as IDbCommand or IDbParameter in your code. However, In the .NET 1.1 BCL the only means to obtain references to instances of these interfaces is to directly instantiate the classes, i.e. for SqlServer this would be

 IDbCommand command = new SqlCommand();

One of the classic creational patterns in the GoF Design Patterns book address this situation directly, the Abstract Factory pattern. This approach was applied in the .NET BCL with the introduction of the DbProviderFactory class which contains various factory methods that create the various objects used in ADO.NET programming. In addition, .NET 2.0 introduced new abstract base classes that all ADO.NET providers must inherit from. These base classes provide more core functionality and uniformity across the various providers as compared to the original ADO.NET interfaces.

Spring's database provider abstraction has a similar API to that of .ADO.NET 2.0's DbProviderFactory. The central interface is IDbProvider and it has factory methods that are analogous to those in the DbProviderFactory class except that they return references to the base ADO.NET interfaces. Note that in keeping with the Spring Framework's philosophy, IDbProvider is an interface, and can thus be easily mocked or stubbed as necessary. Another key elements of this interface is ConnectionString property that specifies the specific runtime information necessary to connect to the provider. The interface also has a IDbMetadata property that contains minimal database metadata information needed to support the functionality in rest of the Spring ADO.NET framework. It is unlikely you will need to use the DatabaseMetadata class directly in your application.

For more information on configuring a Spring database provider refer to Chapter 19, DbProvider

20.3.1. Creating an instance of IDbProvider

Each database vendor is associated with a particular implementation of the IDbProvider interfaces. A variety of implementations are provided with Spring such as SqlServer, Oracle and MySql. Refer to the documentation on Spring's DbProvider for creating a configuration for database that is not yet provided. The programmatic way to create an IDbProvider is shown below

IDbProvider dbProvider = DbProviderFactory.GetDbProvider("System.Data.SqlClient");

Please refer to the Chapter 19, DbProvider for information on how to create a IDbProvider in Spring's XML configuration file.

20.4. Namespaces

The ADO.NET framework consists of a few namespaces, namely Spring.Data, Spring.Data.Generic, Spring.Data.Common, Spring.Data.Support, and Spring.Data.Object.

The Spring.Data namespace contains the majority of the classes and interfaces you will deal with on a day to day basis.

The Spring.Data.Generic namespaces add generic versions of some classes and interfaces and you will also likely deal with this on a day to day basis if you are using .NET 2.0

The Spring.Data.Common namespaces contains Spring's DbProvider abstraction in addition to utility classes for parameter creation.

The Spring.Data.Object namespaces contains classes that represent RDBMS queries, updates, and stored procedures as thread safe, reusable objects.

Finally the Spring.Data.Support namespace is where you find the IAdoExceptionTransactor translation functionality and some utility classes.

20.5. Approaches to Data Access

Spring provides two styles to interact with ADO.NET. The first is a 'template' based approach in which you create an single instance of AdoTemplate to be used by all your DAO implementations. Your DAO methods are frequently implemented as a single method call on the template class as described in detail in the following section. The other approach a more object-oriented manner that models database operations as objects. For example, one can encapsulate the functionality of a data base query via an AdoQuery class and a create/update/delete operation as a AdoNonQuery class. Stored procedures are also model in this manner via the class StoredProcedure. To use these classes you inherit from them and define the details operation in the constructor and implement and abstract method. This reads very cleanly when looking at DAO method implementation as you can generally see all the details of what is going on.

Generally speaking, experience has shown that the AdoTemplate approach reads very cleanly when looking at DAO method implementation as you can generally see all the details of what is going on as compared to the object based approach. The object based approach however, offers some advantages when calling stored procedures since it acts as a cache of derived stored procedure arguments and can be invoked passing a variable length argument list to the 'execute' method. As always, take a look at both approaches and use the approach that provides you with the most benefit for a particular situation.

20.6. Introduction to AdoTemplate

The class AdoTemplate is at the heart of Spring's ADO.NET support. It is based on an Inversion of Control (i.e. callback) design with the central method 'Execute' handing you a IDbCommand instance that has its Connection and Transaction properties set based on the transaction context of the calling code. All resource management is handled by the framework, you only need to focus on dealing with the IDbCommand object. The other methods in this class build upon this central 'Execute' method to provide you a quick means to execute common data access scenarios.

There are two implementations of AdoTemplate. The one that uses Generics and is in the namespace Spring.Data.Generic and the other non-generic version in Spring.Data. In either case you create an instance of an AdoTemplate by passing it a IDbProvider instance as shown below

AdoTemplate adoTemplate = new AdoTemplate(dbProvider);

AdoTemplate is a thread-safe class and as such a single instance can be used for all data access operations in you applications DAOs. AdoTemplate implements an IAdoOperations interface. Although the IAdoOpertions interface is more commonly used for testing scenarios you may prefer to code against instead of the direct class instance.

If you are using the generic version of AdoTemplate you can access the non-generic version via the property ClassicAdoTemplate.

The following two sections show basic usage of the AdoTempate 'Execute' API for .NET 1.1 and 2.0.

20.6.1. Execute Callback

The Execute method and its associated callback function/inteface is the basic method upon which all the other methods in AdoTemplate delegate their work. If you can not find a suitable 'one-liner' method in AdoTemplate for your purpose you can always fall back to the Execute method to perform any database operation while benefiting from ADO.NET resource management and transaction enlistment. This is commonly the case when you are using special provider specific features, such as XML or BLOB support.

20.6.2. Execute Callback in .NET 2.0

In this example a simple query against the 'Northwind' database is done to determine the number of customers who have a particular postal code.

public int FindCountWithPostalCode(string postalCode)
  return adoTemplate.Execute<int>(delegate(DbCommand command)
             command.CommandText =
                 "select count(*) from Customers where PostalCode = @PostalCode";
             DbParameter p = command.CreateParameter();
             p.ParameterName = "@PostalCode";
             p.Value = postalCode;
             return (int)command.ExecuteScalar();



The DbCommand that is passed into the anonymous delegate is already has it Connection property set to the corresponding value of the dbProvider instance used to create the template. Furthermore, the Transaction property of the DbCommand is set based on the transactional calling context of the code as based on the use of Spring's transaction management features. Also note the feature of anonymous delegates to access the variable 'postalCode' which is defined 'outside' the anonymous delegate implementation. The use of anonymous delegates is a powerful approach since it allows you to write compact data access code. If you find that your callback implementation is getting very long, it may improve code clarity to use an interfaced based version of the callback function, i.e. an ICommandCallback shown below.

As you can see, only the most relevant portions of the data access task at hand need to be coded. (Note that in this simple example you would be better off using AdoTemplate's ExecuteScalar method directly. This method is described in the following sections). As mentioned before, the typical usage scenario for the Execute callback would involve downcasting the passed in DbCommand object to access specific provider API features.

There is also an interface based version of the execute method. The signatures for the delegate and interface are shown below

public delegate T CommandDelegate<T>(DbCommand command);  

public interface ICommandCallback
  T DoInCommand<T>(DbCommand command);

While the delegate version offers the most compact syntax, the interface version allows for reuse. The corresponding method signatures on Spring.Data.Generic.AdoTemplate are shown below

public class AdoTemplate : AdoAccessor, IAdoOperations

   T Execute<T>(ICommandCallback action);

   T Execute<T>(CommandDelegate<T> del);


While it is common for .NET 2.0 ADO.NET provider implementations to inherit from the base class System.Data.Common.DbCommand, that is not a requirement. To accomodate the few that don't, which as of this writing are the latest Oracle (ODP) provider, Postgres, and DB2 for iSeries, two additional execute methods are provided. The only difference is the use of callback and delegate implementations that have IDbCommand and not DbCommand as callback arguments. The following listing shows these methods on AdoTemplate.

public class AdoTemplate : AdoAccessor, IAdoOperations

   T Execute<T>(IDbCommandCallback action);

   T Execute<T>(IDbCommandDelegate<T> del);


where the signatures for the delegate and interface are shown below

public delegate T IDbCommandDelegate<T>(IDbCommand command);

public interface IDbCommandCallback<T>
  T DoInCommand(IDbCommand command);

Internally the AdoTemplate implementation delegates to implementations of IDbCommandCallback so that the 'lowest common denominator' API is used to have maximum portability. If you accidentially call Execute<T>(ICommandCallback action)and the command does not inherit from DbCommand, an InvalidDataAccessApiUsageException will be thrown.

Depending on how portable you would like your code to be, you can choose among the two callback styles. The one based on DbCommand has the advantage of access to the more user friendly DbParameter class as compared to IDbParameter obtained from IDbCommand.

20.6.3. Execute Callback in .NET 1.1


AdoTemplate differs from its .NET 2.0 generic counterpart in that it exposes the interface IDbCommand in its 'Execute' callback methods and delegate as compared to the abstract base class DbProvider. Also, since anonymous delegates are not available in .NET 1.1, the typical usage pattern requires you to create a explicitly delegate and/or class that implements the ICommandCallback interface. Example code to query In .NET 1.1 the 'Northwind' database is done to determine the number of customers who have a particular postal code is shown below.

public virtual int FindCountWithPostalCode(string postalCode)
  return (int) AdoTemplate.Execute(new PostalCodeCommandCallback(postalCode));

and the callback implementation is

private class PostalCodeCommandCallback : ICommandCallback
    private string cmdText = "select count(*) from Customer where PostalCode = @PostalCode";

    private string postalCode;
    public PostalCodeCommandCallback(string postalCode)
        this.postalCode = postalCode;

    public object DoInCommand(IDbCommand command)
        command.CommandText = cmdText;

        IDbDataParameter p = command.CreateParameter();
        p.ParameterName = "@PostalCode";
        p.Value = postalCode;
        return command.ExecuteScalar();


Note that in this example, one could more easily use AdoTemplate's ExecuteScalar method.

The Execute method has an interface and delegate overloads. The signatures for the delegate and interface are shown below

public delegate object CommandDelegate(IDbCommand command);

public interface ICommandCallback
  object DoInCommand(IDbCommand command);

The corresponding method signatures on Spring.Data.AdoTemplate are shown below

public class AdoTemplate : AdoAccessor, IAdoOperations

   object Execute(CommandDelegate del);

   object Execute(ICommandCallback action);



Note that you have to cast to the appropriate object type returned from the execute method.

20.6.4. Quick Guide to AdoTemplate Methods

There are many methods in AdoTemplate so it is easy to feel a bit overwhelmed when taking a look at the SDK documentation. However, after a while you will hopefully find the class 'easy to navigate' with intellisence. Here is a quick categorization of the method names and their associated data access operation. Each method is overloaded to handle common cases of passing in parameter values.

The generic 'catch-all' method

  • Execute - Allows you to perform any data access operation on a standard DbCommand object. The connection and transaction properties of the DbCommand are already set based on the transactional calling context. There is also an overloaded method that operates on a standard IDbCommand object. This is for those providers that do not inherit from the base class DbCommand.

The following methods mirror those on the DbCommand object.

  • ExecuteNonQuery - Executes the 'NonQuery' method on a DbCommand, applying provided parameters and returning the number of rows affected.

  • ExecuteScalar - Executes the 'Scalar' method on a DbCommand, applying provided parameters, and returning the first column of the first row in the result set.

Mapping result sets to objects

  • QueryWithResultSetExtractor - Execute a query mapping a result set to an object with an implementation of the IResultSetExtractor interface.

  • QueryWithResultSetExtractorDelegate - Same as QueryWithResultSetExtractor but using a ResultSetExtractorDelegate to perform result set mapping.

  • QueryWithRowCallback - Execute a query calling an implementation of IRowCallback for each row in the result set.

  • QueryWithRowCallbackDelegate - Same as QueryWithRowCallback but calling a RowCallbackDelegate for each row.

  • QueryWithRowMapper - Execute a query mapping a result set on a row by row basis with an implementation of the IRowMapper interface.

  • QueryWithRowMapperDelegate - Same as QueryWithRowMapper but using a RowMapperDelegate to perform result set row to object mapping.

Mapping result set to a single object

  • QueryForObject - Execute a query mapping the result set to an object using a IRowMapper. Exception is thrown if the query does not return exactly one object.

Query with a callback to create the DbCommand object. These are generally used by the framework itself to support other functionality, such as in the Spring.Data.Objects namespace.

  • QueryWithCommandCreator - Execute a query with a callback to IDbCommandCreator to create a IDbCommand object and using either a IRowMapper or IResultSetExtractor to map the result set to an object. One variation lets multiple result set 'processors' be specified to act on multiple result sets and return output parameters.

DataTable and DataSet operations

  • DataTableCreate - Create and Fill DataTables

  • DataTableFill - Fill a pre-existing DataTable.

  • DataTableUpdateWithCommandBuilder - Update the database using the provided DataTable, select SQL, and parameters.

  • DataSetCreate - Create and Fill DataSets

  • DataSetFill - Fill a pre-existing DataSet

  • DataSetUpdateWithCommandBuilder - Update the database using the provided DataSet, select SQL, and parameters.

    NOTE: These methods are not currently in the generic version of AdoTemplate but accessible through the property ClassicAdoTemplate.

Parameter Creation utility methods

  • DeriveParameters - Derive the parameter collection for stored procedures.

In turn each method typically has four overloads, one with no parameters and three for providing parameters. Aside from the DataTable/DataSet operations, the three parameter overloads are of the form shown below

  • MethodName(CommandType cmdType, string cmdText, CallbackInterfaceOrDelegate, parameter setting arguments)

The CallbackInterfaceOrDelegate is one of the three types listed previously. The parameters setting arguments are of the form

  • MethodName( ... string parameterName, Enum dbType, int size, object parameterValue)

  • MethodName( ... IDbParameters parameters)

  • MethodName( ... ICommandSetter commandSetter)

The first overload is a convenience method when you only have one parameter to set. The database enumeration is the base class 'Enum' allowing you to pass in any of the provider specific enumerations as well as the common DbType enumeration. This is a trade off of type-safety with provider portability. (Note generic version could be improved to provide type safety...).

The second overload contains a collection of parameters. The data type is Spring's IDbParameters collection class discussed in the following section.

The third overload is a callback interface allowing you to set the parameters (or other properties) of the IDbCommand passed to you by the framework directly. (TODO provide delegate version of ICommandSetter.)

If you are using .NET 2.0 the delegate versions of the methods are very useful since very compact definitions of database operations can be created that reference variables local to the DAO method. This removes some of the tedium in passing parameters around with interface based versions of the callback functions since they need to be passed into the constructor of the implementing class. The general guideline is to use the delegate when available for functionality that does not need to be shared across multiple DAO classes or methods and use interface based version to reuse the implementation in multiple places. The .NET 2.0 versions make use of generics where appropriate and therefore enhance type-safety.

20.7. Transaction Management

The AdoTemplate is used in conjunction with an implementation of a IPlatformTransactionManager, which is Spring's portable transaction management API. This section gives a brief overview of the transaction managers you can use with AdoTemplate and the details of how you can retrieve the connection/transaction ADO.NET objects that are bound to the thread when a transaction starts. Please refer to the section key abstractions in the chapter on transactions for more comprehensive introduction to transaction management.

To use local transactions, those with only one transactional resource (i.e. the database) you will typically use AdoPlatformTransactionManager. If you need to mix Hibernate and ADO.NET data access operations within the same local transaction you should use HibernatePlatformTransaction manager which is described more in the section on ORM transaction management.

While it is most common to use Spring's transaction management features to avoid the low level management of ADO.NET connection and transaction objects, you can retrieve the connection/transaction pair that was created at the start of a transaction and bound to the current thread. This maybe useful for some integration with other data access APIs. The can be done using the utility class ConnectionUtils as shown below.

IDbProvider dbProvider = DbProviderFactory.GetDbProvider("System.Data.SqlClient");
ConnectionTxPair connectionTxPairToUse = ConnectionUtils.GetConnectionTxPair(dbProvider);

IDbCommand command = DbProvider.CreateCommand();
command.Connection = connectionTxPairToUse.Connection;
command.Transaction = connectionTxPairToUse.Transaction;

It is possible to provide a wrapper around the standard .NET provider interfaces such that you can use the plain ADO.NET API in conjunction with Spring's transaction management features. This functionality will be available in a future release.

If you are using ServiceDomainPlatformTransactionManager or TxScopePlatformTransactionManager then you can retrieve the currently executing trasaction object via the standard .NET APIs.

20.8. Exception Translation

AdoTemplate's methods throw exceptions within a Data Access Object (DAO) exception hierarchy described in Chapter 18, DAO support. In addition, the command text and error code of the exception are extracted and logged. This leads to easier to write a provider independent exception handling layer since the exceptions thrown are not tied to a specific persistence technology. Additionally, for ADO.NET code the error messages logged provide information on the SQL and error code to better help diagnose the issue. (Logging of parameter values is to be implemented in the next release).

20.9. Parameter Management

A fair amount of the code in ADO.NET applications is related to the creation and population of parameters. The BCL parameter interfaces are very minimal and do not have many convenience methods found in provider implementations such as SqlClient. Even still, with SqlClient, there is a fair amount of verbosity to creating and populating a parameter collection. Spring provides two ways to make this mundane task easier and more portable across providers.

20.9.1. IDbParametersBuilder

Instead of creating a parameter on one line of code, then setting its type on another and size on another, a builder and parameter interface, IDbParametersBuilder and IDbParameter respectfully, are provided so that this declaration process can be condensed. The IDbParameter support chaining calls to its methods, in effect a simple language-constrained domain specific language, to be fancy about it. Here is an example of it in use.

IDbParametersBuilder builder = CreateDbParametersBuilder();

// now get the IDbParameters collection for use in passing to AdoTemplate methods.

IDbParameters parameters = builder.GetParameters();

Please note that IDbParameters and IDbParameter are not part of the BCL, but part of the Spring.Data.Common namespace. The IDbParameters collection is a frequent argument to the overloaded methods of AdoTemplate.

The parameter prefix, i.e. '@' in Sql Server, is not required to be added to the parameter name. The DbProvider is aware of this metadata and AdoTemplate will add it automatically if required before execution.

An additional of the IDbParametersBuilder is to create a Spring FactoryObject that creates IDbParameters for use in the XML configuration file of the IoC container. By leveraging Spring's expression evaluation language, the above lines of code can be taken as text from the XML configuration file and executed. As a result you can externalize your parameter definitions from your code. In combination with abstract object definitions and importing of configuration files your increase the chances of having one code base support multiple database providers just by a change in configuration files. Explicit support for this functionality will be in the final release.

20.9.2. IDbParameters

This class is similar to the parameter collection class you find in provider specific implementations of IDataParameterCollection. It contains a variety of convenience methods to build up a collection of parameters.

Here is an abbreviated listing of the common convenience methods.

  • int Add(object parameterValue)

  • void AddRange(Array values)

  • IDbDataParameter AddWithValue(string name, object parameterValue)

  • IDbDataParameter Add(string name, Enum parameterType)

  • IDbDataParameter AddOut(string name, Enum parameterType)

  • IDbDataParameter AddReturn(string name, Enum parameterType)

  • void DeriveParameters(string storedProcedureName)

Here a simple usage example

// inside method has has local variable country and city...

IDbParameters parameters = CreateDbParameters();
parameters.AddWithValue("Country", country).DbType = DbType.String;
parameters.Add("City", DbType.String).Value = city;

// now pass on to AdoTemplate methods.

The parameter prefix, i.e. '@' in Sql Server, is not required to be added to the parameter name. The DbProvider is aware of this metadata and AdoTemplate will add it automatically if required before execution.

20.10. Mapping DBNull values

When reading from a IDataReader there is often the need to map DBNull values to some default values, i.e. null or say a magic number such as -1. This is usually done via a ternary operator which decreases readability and also increases the likelyhood of mistakes. Spring provides an IDataReaderWrapper interface (which inherits from the standard IDataReader) so that you can provide your own implementation of a IDataReader that will perform DBNull mapping for you in a consistent and non invasive manner to your result set reading code. A default implementation, NullMappingDataReader is provided which you can subclass to customize or simply implement the IDataReaderWrapper interface directly. This interface is shown below

	public interface IDataReaderWrapper : IDataReader
	    IDataReader WrappedReader

All of AdoTemplates callback interfaces/delegates that have an IDataReader as an argument are wrapped with a IDataReaderWrapper if the AdoTemplate has been configured with one via its DataReaderWrapperType property. Your implementation should support a zero-arg constructor.

Frequently you will use a common mapper for DBNull across your application so only one instance of AdoTemplate and IDataReaderWrapper in required. If you need to use multiple null mapping strategies you will need to create multiple instances of AdoTemplate and configure them appropriately in the DAO objects.

20.11. Basic data access operations

The 'ExecuteNonQuery' and 'ExecuteScalar' methods of AdoTemplate have the same functionality as the same named methods on the DbCommand object

20.11.1. ExecuteNonQuery

ExecuteNonQuery is used to perform create, update, and delete operations. It has four overloads listed below reflecting different ways to set the parameters.

An example of using this method is shown below

        public void CreateCredit(float creditAmount)
                    String.Format("insert into Credits(creditAmount) VALUES ({0})",

20.11.2. ExecuteScalar

An example of using this method is shown below

int iCount = (int)adoTemplate.ExecuteScalar(CommandType.Text, "SELECT COUNT(*) FROM TestObjects");

20.12. Queries and Lightweight Object Mapping

A common ADO.NET development task is reading in a result set and converting it to a collection of domain objects. The family of QueryWith methods on AdoTemplate help in this task. The responsibility of performing the mapping is given to one of three callback interfaces/delegates that you are responsible for developing. These callback interfaces/delegates are:

  • IResultSetExtractor / ResultSetExtractorDelegate - hands you a IDataReader object for you to iterate over and return a result object.

  • IRowCallback / RowCallbackDelegate - hands you a IDataReader to process the current row. Returns void and as such is usually stateful in the case of IRowCallback implementations or uses a variables to collect result that is available to an anonymous delegate.

  • IRowMapper / RowMapperDelegate - hands you a IDataReader to process the current row and return an object corresponding to that row.

There are generic versions of the IResultSetExtractor and IRowMapper interfaces/delegates proving you with additional type-safety as compared to the object based method signatures used in the .NET 1.1 implementation.

As usual with callback APIs in Spring.Data, you implementations of these interfaces/delegates are only concerned with the core task at hand - mapping data - while the framework handles iteration of readers and resource management.

Each 'QueryWith' method has 4 overloads to handle common ways to bind parameters to the command text.

The following sections describe in more detail how to use Spring's lightweight object mapping framework.

20.12.1. ResultSetExtractor

The ResultSetExtractor gives you control to iterate over the IDataReader returned from the query. You are responsible for iterating through all the result sets and returning a corresponding result object. Implementations of IResultSetExtractor are typically stateless and therefore reusable as long as the implementation doesn't access stateful resources. The framework will close the IDataReader for you.

The interface and delegate signature for ResutSetExtractors is shown below for the generic version in the Spring.Data.Generic namespace

public interface IResultSetExtractor<T>
  T ExtractData(IDataReader reader);

public delegate T ResultSetExtractorDelegate<T>(IDataReader reader);

The definition for the non-generic version is shown below

public interface IResultSetExtractor
    object ExtractData(IDataReader reader);

public delegate object ResultSetExtractorDelegate(IDataReader reader);

Here is an example taken from the Spring.DataQuickStart. It is a method in a DAO class that inherits from AdoDaoSupport, which has a convenience method 'CreateDbParametersBuilder()'.

        public virtual IList<string> GetCustomerNameByCountryAndCityWithParamsBuilder(string country, string city)

            IDbParametersBuilder builder = CreateDbParametersBuilder();
            return AdoTemplate.QueryWithResultSetExtractor(CommandType.Text,
                                                           new CustomerNameResultSetExtractor<List<string>>(),

The implementation of the ResultSetExtractor is shown below.

    internal class CustomerNameResultSetExtractor<T> : IResultSetExtractor<T> where T : IList<string>, new()

        public T ExtractData(IDataReader reader)
            T customerList = new T();
            while (reader.Read())
                string contactName = reader.GetString(0);
            return customerList;

Internally the implementation of the QueryWithRowCallback and QueryWithRowMapper methods are specializations of the general ResultSetExtractor. For example, the QueryWithRowMapper implementation iterates through the result set, calling the callback method 'MapRow' for each row and collecting the results in an IList. If you have a specific case that is not covered by the QueryWithXXX methods you can subclass AdoTemplate and follow the same implementation pattern to create a new QueryWithXXX method to suit your needs.

20.12.2. RowCallback

The RowCallback is usually a statefull object itself or populates another stateful object that is accessible to the calling code. Here is a sample take from the Data QuickStart

    public class RowCallbackDao : AdoDaoSupport
        private string cmdText = "select ContactName, PostalCode from Customers";

        public virtual IDictionary<string, IList<string>> GetPostalCodeCustomerMapping()
            PostalCodeRowCallback statefullCallback = new PostalCodeRowCallback();
            AdoTemplate.QueryWithRowCallback(CommandType.Text, cmdText,

            // Do something with results in stateful callback...
            return statefullCallback.PostalCodeMultimap;

The PostalCodeRowCallback builds up state which is then retrieved via the property PostalCodeMultimap. The Callback implementation is shown below

    internal class PostalCodeRowCallback : IRowCallback
        private IDictionary<string, IList<string>> postalCodeMultimap =
            new Dictionary<string, IList<string>>();

        public IDictionary<string, IList<string>> PostalCodeMultimap
            get { return postalCodeMultimap; }

        public void ProcessRow(IDataReader reader)
            string contactName = reader.GetString(0);
            string postalCode = reader.GetString(1);
            IList<string> contactNameList;
            if (postalCodeMultimap.ContainsKey(postalCode))
                contactNameList = postalCodeMultimap[postalCode];
                postalCodeMultimap.Add(postalCode, contactNameList = new List<string>());

20.12.3. RowMapper

The RowMapper lets you focus on just the logic to map a row of your result set to an object. The creation of a IList to store the results and iterating through the IDataReader is handled by the framework. Here is a simple example taken from the Data QuickStart application

    public class RowMapperDao : AdoDaoSupport
        private string cmdText = "select Address, City, CompanyName, ContactName, " +
                             "ContactTitle, Country, Fax, CustomerID, Phone, PostalCode, " +
                             "Region from Customers";

        public virtual IList<Customer> GetCustomers()
            return AdoTemplate.QueryWithRowMapper<Customer>(CommandType.Text, cmdText,
                                                  new CustomerRowMapper<Customer>());

where the implementation of the RowMapper is

    public class CustomerRowMapper<T> : IRowMapper<T> where T : Customer, new()
        public T MapRow(IDataReader dataReader, int rowNum)
            T customer = new T();
            customer.Address = dataReader.GetString(0);
            customer.City = dataReader.GetString(1);
            customer.CompanyName = dataReader.GetString(2);
            customer.ContactName = dataReader.GetString(3);
            customer.ContactTitle = dataReader.GetString(4);
            customer.Country = dataReader.GetString(5);
            customer.Fax = dataReader.GetString(6);
            customer.Id = dataReader.GetString(7);
            customer.Phone = dataReader.GetString(8);
            customer.PostalCode = dataReader.GetString(9);
            customer.Region = dataReader.GetString(10);
            return customer;

You may also pass in a delegate, which is particularly convenient if the mapping logic is short and you need to access local variables within the mapping logic.

        public virtual IList<Customer> GetCustomersWithDelegate()
            return AdoTemplate.QueryWithRowMapperDelegate<Customer>(CommandType.Text, cmdText,
                        delegate(IDataReader dataReader, int rowNum)
                                Customer customer = new Customer();
                                customer.Address = dataReader.GetString(0);
                                customer.City = dataReader.GetString(1);
                                customer.CompanyName = dataReader.GetString(2);
                                customer.ContactName = dataReader.GetString(3);
                                customer.ContactTitle = dataReader.GetString(4);
                                customer.Country = dataReader.GetString(5);
                                customer.Fax = dataReader.GetString(6);
                                customer.Id = dataReader.GetString(7);
                                customer.Phone = dataReader.GetString(8);
                                customer.PostalCode = dataReader.GetString(9);
                                customer.Region = dataReader.GetString(10);
                                return customer;

20.12.4. Query for a single object

The QueryForObject method is used when you expect there to be exactly one object returned from the mapping, otherwise a Spring.Dao.IncorrectResultSizeDataAccessException will be thrown. Here is some sample usage taken from the Data QuickStart.

    public class QueryForObjectDao : AdoDaoSupport
        private string cmdText = "select Address, City, CompanyName, ContactName, " +
                     "ContactTitle, Country, Fax, CustomerID, Phone, PostalCode, " +
                     "Region from Customers where ContactName = @ContactName";
        public Customer GetCustomer(string contactName)
            return AdoTemplate.QueryForObject(CommandType.Text, cmdText, 
                                              new CustomerRowMapper<Customer>(),
                                              "ContactName", DbType.String, 30, contactName);

20.12.5. Query using a CommandCreator

There is a family of overloaded methods that allows you to encapsulate and reuse a particular configuration of a IDbCommand object. This methods also allow for access to returned out parameters as well as a method that allows processing of multiple result sets. These methods used internally to support the class in the Spring.Data.Objects namespace and you may find the API used in that namespace to be more convenient. The family of methods is listed below.

  • object QueryWithCommandCreator(IDbCommandCreator cc, IResultSetExtractor rse)

  • void QueryWithCommandCreator(IDbCommandCreator cc, IRowCallback rowCallback)

  • IList QueryWithCommandCreator(IDbCommandCreator cc, IRowMapper rowMapper)

There is also the same methods with an additional collecting parameter to obtain any output parameters. These are

  • object QueryWithCommandCreator(IDbCommandCreator cc, IResultSetExtractor rse, IDictionary returnedParameters)

  • void QueryWithCommandCreator(IDbCommandCreator cc, IRowCallback rowCallback, IDictionary returnedParameters)

  • IList QueryWithCommandCreator(IDbCommandCreator cc, IRowMapper rowMapper, IDictionary returnedParameters)

The IDbCommandCreator callback interface is shown below

	public interface IDbCommandCreator 
	    IDbCommand CreateDbCommand();

The created IDbCommand object is used when performing executing the QueryWithCommandCreator method.

To process multiple result sets specify a list of named result set processors,( i.e. IResultSetExtractor, IRowCallback, or IRowMapper). This method is shown below

  • IDictionary QueryWithCommandCreator(IDbCommandCreator cc, IList namedResultSetProcessors)

The list must contain objects of the type Spring.Data.Support.NamedResultSetProcessor. This is the class responsible for associating a name with to a result set processor. The constructors are listed below.

public class NamedResultSetProcessor  {
  public NamedResultSetProcessor(string name, IRowMapper rowMapper) { ... }

  public NamedResultSetProcessor(string name, IRowCallback rowcallback)  { ... } 

  public NamedResultSetProcessor(string name, IResultSetExtractor resultSetExtractor) { ... }

  . . . 


The results of the RowMapper or ResultSetExtractor are retrieved by name from the dictionary that is returned. RowCallbacks, being stateless, only have the placeholder text, "ResultSet returned was processed by an IRowCallback" as a value for the name of the RowCallback used as a key. Output and InputOutput parameter can be retrieved by name. If this parameter name is null, then the index of the parameter prefixed with the letter 'P' is a key name, i.e P2, P3, etc. name

The namespace Spring.Data.Objects.Generic contains generic versions of these methods. These are listed below

  • T QueryWithCommandCreator<T>(IDbCommandCreator cc, IResultSetExtractor<T> rse)

  • IList<T> QueryWithCommandCreator<T>(IDbCommandCreator cc, IRowMapper<T> rowMapper)

and overloads that have an additional collecting parameter to obtain any output parameters.

  • T QueryWithCommandCreator<T>(IDbCommandCreator cc, IResultSetExtractor<T> rse, IDictionary returnedParameters)

  • IList<T> QueryWithCommandCreator<T>(IDbCommandCreator cc, IRowMapper<T> rowMapper, IDictionary returnedParameters)

When processing multiple result sets you can specify up to two type safe result set processors.

  • IDictionary QueryWithCommandCreator<T>(IDbCommandCreator cc, IList namedResultSetProcessors)

  • IDictionary QueryWithCommandCreator<T,U>(IDbCommandCreator cc, IList namedResultSetProcessors)

The list of result set processors contains either objects of the type Spring.Data.Generic.NamedResultSetProcessor<T> or Spring.Data.NamedResultSetProcessor. The generic result set processors, NamedResultSetProcessor<T>, is used to process the first result set in the caes of using QueryWithCommandCreator<T> and to process the first and second result set in the case of using QueryWithCommandCreator<T,U>. Additional Spring.Data.NamedResultSetProcessor that are listed can be used to process additional result sets. If you specify a RowCallback with NamedResultSetProcessor<T>, you still need to specify a type parameter (say string) because the RowCallback processor does not return any object. It is up to subclasses of RowCallback to collect state due to processing the result set which is later queried.

20.13. DataTable and DataSet

There are methods to help perform common DataTable and DataSet operations. Please refer to the SDK documentation at this time.

20.13.1. DataTables


20.13.2. DataSets


20.14. TableAdapters and participation in transactional context

TypedDataSets need to have commands in their internal DataAdapters and command collections explicitly set with a connection/transaction in order for them to correctly participate with a surrounding transactional context. The reason for this is by default the code generated is explicitly managing the connections and transactions. This issue is very well described in the article System.Transactions and ADO.NET 2.0 by ADO.NET guru Sahil Malik. Spring offers a convenience method that will use reflection to internally set the transaction on the table adapter's internal command collection to the ambient transaction. This method on the class Spring.Data.Support.TypedDataSetUtils and is named ApplyConnectionAndTx. Here is sample usage of a DAO method that uses a VS.NET 2005 generated typed dataset for a PrintGroupMapping table.

public PrintGroupMappingDataSet FindAll()

   PrintGroupMappingTableAdapter adapter = new PrintGroupMappingTableAdapter();
   PrintGroupMappingDataSet printGroupMappingDataSet = new PrintGroupMappingDataSet();
   printGroupMappingDataSet = AdoTemplate.Execute(delegate(IDbCommand command)
                                  TypedDataSetUtils.ApplyConnectionAndTx(adapter, command);
                                  return printGroupMappingDataSet;
                              as PrintGroupMappingDataSet;

   return printGroupMappingDataSet;

This DAO method may be combined with other DAO operations inside a transactional context and they will all share the same connection/transaction objects.

20.15. Deriving Stored Procedure Parameters


20.16. Database operations as Objects


20.16.1. AdoNonQuery


20.16.2. AdoQuery


20.16.3. MappingAdoQuery


20.16.4. Stored Procedure

The StoredProcedure class allows you to call and extract the results of a stored procedure with very little code. The ability to derive the parameters programmatically and cache them for later results in much less boiler plate code that you have to write. You can of course define the parameters explicitly if you choose to do so.

The methods you can execute on a stored procedure fall into three categories

  • ExecuteScalar

  • ExecuteNonQuery

  • Query using Spring's object mapping framework.

Each of these methods returns an IDictionary that contains the output parameters and/or any results from Spring's object mapping framework. The arguments to these methods can be a variable length argument list, in which case the order must match the parameter order of the stored procedure, or a IDictionary with parameter key/value pairs. In the latter case the method names are suffixed with the work 'ByNamedParamter'.

Lets take a look at an example. The following stored procedure class will call the CustOrdersDetail stored procedure in the Northwind database, passing in the OrderID as a stored procedure argument and returning a collection of OrderDetails business objects.

    public class CustOrdersDetailStoredProc : StoredProcedure
        private static string procedureName = "CustOrdersDetail";

        public CustOrdersDetailStoredProc(IDbProvider dbProvider) : base(dbProvider, procedureName)
            AddRowMapper("orderDetailRowMapper", new OrderDetailRowMapper() );
        public virtual IList GetOrderDetails(int orderid)
            IDictionary outParams = Query(orderid);
            return outParams["orderDetailRowMapper"] as IList;


The 'DeriveParameters' method saves you the trouble of having to declare each parameter explicitly. When using DeriveParameters is it often common to use the Query method that takes a variable length list of arguments. This assumes additional knowledge on the order of the stored procedure arguments. If you do not want to follow this loose shorthand convention, you can call the method QueryByNamesParameters instead passing in a IDictionary of parameter key/value pairs.

The StoredProcedure class are threadsafe once 'compiled', an act which is usually done in the constructor. This sets up the cache of database parameters that can be used on each call to Query. The implementation of IRowMapper that is used to extract the business objects is 'registered' with the class and then later retrieved by name as a fictional output parameter. You may also register IRowCallback and IResultSetExtractor callback interfaces via the AddRowCallback and AddResultSetExtractor methods.

Return values from stored procedures are contained under the key "RETURN_VALUE".

20.16.5. DataSetOperation