DbCommand和参数化SQL,ORACLE vs SQL Server

我有一个应用程序,除其他外,将各种数据存储到数据库中。 数据库可能是ORACLE或SQL Server。 SQL是根据执行期间获取的配置和值动态创建的。

通过使用DbProviderFactory,我的db方法可以使用ORACLE或SQL Server,而无需为任何数据库编写自定义代码,除了一件事; 参数/绑定变量。 对于ORACLE,我需要使用":ParameterName"而对于SQL Server,我需要使用"@ParameterName" 。 有没有办法让这个通用?

示例代码:

 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(); } 

我很久以前就接受了这个问题的答案,但出于某种原因,答案已经不在了……所以我想我需要回答我自己的问题。

我做的是创建一个parambuilder类:

 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; } } 

我创建了ParamBuilder类型的成员变量:

 private readonly ParamBuilder m_ParamBuilder; 

然后在我使用参数的方法中,我使用如下:

 ... 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); ... 

创建一个抽象属性以获取“值”循环中使用的格式字符串。

 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}"; }} 

如果你想要快速和肮脏,只需要投入另一种选择。

 string sql = select * from foo there foo.id = @id; if (isOracle) { sql = replaceAll(sql,"@",":"); }