DbCommand and parameterized SQL, ORACLE vs SQL Server

12,088

Solution 1

I accepted an answer for this question long ago, but for some reason that answer is no longer here... So I guess I need to answer my own question.

What I did was to create a parambuilder class:

class ParamBuilder
{
    private DbProviderFactory m_factory;
    private DbCommandBuilder m_builder;
    private string m_parameterMarkerFormat;
    public ParamBuilder(DbProviderFactory factory) : this(factory, null)
    {
    }

    public ParamBuilder(DbProviderFactory factory, DbConnection source)
    {
        m_factory = factory;
        m_builder = m_factory.CreateCommandBuilder();
        if (source != null)
        {
            using (DataTable tbl =
                source.GetSchema(DbMetaDataCollectionNames.DataSourceInformation))
            {
                m_parameterMarkerFormat =  
                    tbl.Rows[0][DbMetaDataColumnNames.ParameterMarkerFormat] as string;
            }
        }
        if (String.IsNullOrEmpty(m_parameterMarkerFormat))
            m_parameterMarkerFormat = "{0}";
    }

    public DbParameter CreateParameter(string parameterName, 
        out string parameterMarker)
    {
        DbParameter param = m_factory.CreateParameter();
        param.ParameterName =  
            (string)typeof(DbCommandBuilder).InvokeMember("GetParameterName",
                System.Reflection.BindingFlags.Instance |
                System.Reflection.BindingFlags.InvokeMethod |
                System.Reflection.BindingFlags.NonPublic, null, m_builder, 
                new object[] { parameterName });

        parameterMarker = 
            String.Format(System.Globalization.CultureInfo.InvariantCulture, 
            m_parameterMarkerFormat, param.ParameterName);

        return param;
    }

}

I create a member variable of the ParamBuilder type:

private readonly ParamBuilder m_ParamBuilder;

Then in the method where I use parameters, I use it as follows:

...
string paramMarker;
DbParameter param = m_ParamBuilder.CreateParameter(destination[i].ColumnName, 
    out paramMarker);
sql.Append(paramMarker);

param.Direction = ParameterDirection.Input;
param.Value = source[i];
Cmd.Parameters.Add(param);
...

Solution 2

Make an abstract property to get the format string used in the "values" loop.

class DBOperations
 public abstract string ParameterStringFormat;
 ...
for (int i = 0; i < values.Length; i++)
        {        
            sql.Append(String.Format(ParamterStringFormat, columns[i].ColumnName)); // SQL Server
        }  


class SqlDbOperations : DBOperations
 public override string ParameterStringFormat { get { return "@{0}"; }}


class OracleDBOperations : DBOperations
 public override string ParameterStringFormat { get { return ":{0}"; }}
Share:
12,088

Related videos on Youtube

Nils Magne Lunde
Author by

Nils Magne Lunde

Architect/developer that are mostly working with C# and JavaScript these days.

Updated on May 24, 2022

Comments

  • Nils Magne Lunde
    Nils Magne Lunde almost 2 years

    I have an application that will, among other things, store various data into a database. The database might be ORACLE or SQL Server. The SQL is created dynamically based on configuration and values picked up during execution.

    By using DbProviderFactory my db methods are able to work with either ORACLE or SQL Server without writing custom code for any of the databases, except from one thing; parameters/bind variables. For ORACLE I need to use ":ParameterName" whereas for SQL Server I need to use "@ParameterName". Is there any way to make this generic?

    Sample code:

    public class DbOperations
    {
        private DbProviderFactory m_factory;
        private DbConnection m_CN;
    
        ...
    
        private void InsertToDb(ValueType[] values, ColumnType[] columns)
        {     
            DbCommand Cmd = m_factory.CreateCommand();
            Cmd.Connection = m_CN;
    
            StringBuilder sql = new StringBuilder();
            sql.Append("INSERT INTO ");
            sql.Append(DestinationTable);
            sql.Append(" (");
    
            for (int i = 0; i < columns.Length; i++)
            {
                sql.Append(columns[i].ColumnName);
                if (i < columns.Length - 1) 
                sql.Append(", ");
            }
            sql.Append(") VALUES (");
    
            for (int i = 0; i < values.Length; i++)
            {        
                //sql.Append(String.Format(":{0}", columns[i].ColumnName));  //ORACLE
                sql.Append(String.Format("@{0}", columns[i].ColumnName)); // SQL Server
            }       
    
            DbParameter param = m_factory.CreateParameter();
            param.Direction = ParameterDirection.Input;
            param.ParameterName = columns[i].ColumnName;
            param.Value = values[i];
            Cmd.Parameters.Add(param);
    
            if (i < columns.Length - 1)           
                sql.Append(", ");
          }
          sql.Append(")");
          Cmd.CommandText = sql.ToString();
          Cmd.ExecuteNonQuery();
    }
    
  • Václav Starý
    Václav Starý over 8 years