我有一个应用程序,除其他外,将各种数据存储到数据库中。 数据库可能是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();
}
答案 0 :(得分:6)
很久以前我接受了这个问题的答案,但出于某种原因,答案已经不在了......所以我想我需要回答我自己的问题。
我所做的是创建一个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);
...
答案 1 :(得分:2)
创建一个抽象属性以获取“values”循环中使用的格式字符串。
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}"; }}
答案 2 :(得分:0)
如果你想要快速和肮脏,只需要另外选择。
string sql = select * from foo there foo.id = @id;
if (isOracle) {
sql = replaceAll(sql,"@",":");
}