Using Generic ADO.net Data Factories

written by Michael Swain on Tuesday, November 18 2008

Too many samples on the internet only show how to write ADO.Net code for their chosen provider, none really cover the fact that ADO requires a generic factory interface that can make changing database backends as simple as modifying a single file. This allows for any number of database backed to be used, as long as they all support the same SQL syntax, or are close enough that simple type checks can be used to alter the syntax on the fly.

 Below is an example of how to create a generic connection and execute a command using only the connection string defined in app.config and the System.Data.Common namespace:

[Sample code]

string connectionName = "ConnectionString";
System.Configuration.ConnectionStringSettings connectionString = System.Configuration.ConfigurationManager.ConnectionStrings[connectionName];
System.Data.Common.DbProviderFactory factory = System.Data.Common.DbProviderFactories.GetFactory(connectionString.ProviderName);

using (DbConnection connection = factory.CreateConnection())
{
    connection.ConnectionString = connectionString.ConnectionString;
    connection.Open();
    using (DbCommand command = connection.CreateCommand())
    {
        command.CommandText = "SELECT * FROM ATable WHERE BColumn = @BColumn";
        command.CommandType = CommandType.Text;
        DbParameter param = command.CreateParameter();
        param.ParameterName = "BColumn";
        param.Value = 12;
        command.Parameters.Add(param);

        using (DbDataReader reader = command.ExecuteReader())
        {
            while (reader.Read())
            {
                int col = reader.GetOrdinal("AColumn");
                if (!reader.IsDBNull(col))
                {
                    object value = reader[col];
                }
            }
        }

    }
}

[NOTE: To use the above sample on a website all you have to change is replace System.Configuration.ConfigurationManager with System.Web.WebConfigurationManager.]

New backend provider, no problem

Using the above code as an example, if you needed to move your code from VistaDB to SQL server you would only need to change your connection string to one necessary for SQL server and the code will function the same.

It is also possible to provide multiple connection strings in an application and just change the name passed in to switch between them. You could even sync between two different connections as long as both backends support similar SQL syntax.

In the above example I used a command parameter to pass through a value to filter the query by. This is where the syntax requirements are important. Different backends may require different markers for parameters, One way to work around this us to use a CommandBuilder as it will build the SQL syntax for you, however they will also incur a cost as they have to query the backend to get the schema for the table. Depending on the system this can be a slow operation. Also CommandBuilder's only support a very basic table structure and you cannot perform complex joins or aggregates with them, though if your backend supports Views you can build views to handle such complexities then use the CommandBuilder with them.

Some people might mention that they could just use Datasets to get similar results and write less code. Unfortunately, Microsoft decided to not use the generic factories when constructing Datasets and instead the XML for the Dataset is tied to the classname of the underlying backend instead of its generic. This forces you to rebuild the entire Dataset when changing your provider.

 

Similar Posts

  1. Dogfooding, Entity Framework and LINQ
  2. LINQ test for custom IEnumerator
  3. Using SqlBulkCopy to move data from VistaDB to SQL Server

Comments are closed

Options:

Size

Colors