DbCommand 和参数化 SQL、ORACLE 与 SQL Server

发布于 2024-10-21 16:03:55 字数 1654 浏览 1 评论 0原文

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

通过使用 DbProviderFactory,我的数据库方法能够与 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();
}

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

黯然#的苍凉 2024-10-28 16:03:55

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

我所做的是创建一个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);
...

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);
...
梦里兽 2024-10-28 16:03:55

创建一个抽象属性来获取“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}"; }}

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}"; }}
南城追梦 2024-10-28 16:03:55

如果你想要快速而肮脏的话,只需添加另一个选项即可。

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

Just throwing in another option if you want quick and dirty.

string sql = select * from foo there foo.id = @id;
if (isOracle) {
 sql = replaceAll(sql,"@",":");
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文