【问题标题】:Adding parameters to IDbCommand向 IDbCommand 添加参数
【发布时间】:2012-01-04 07:39:20
【问题描述】:

我正在创建一个小的帮助函数来返回 DataTable。我想与ADO.Net 支持的所有提供商合作,所以我考虑让所有东西都尽可能使用IDbCommandDbCommand

我遇到了以下代码的绊脚石:

    private static DataTable QueryImpl(ref IDbConnection conn, String SqlToExecute, CommandType CommandType, Array Parameters)
    {
        SetupConnection(ref conn);
        // set the capacity to 20 so the first 20 allocations are quicker...
        DataTable dt = new DataTable();
        using (IDbCommand cmd = conn.CreateCommand())
        {
            cmd.CommandText = SqlToExecute;
            cmd.CommandType = CommandType;
            if (Parameters != null && Parameters.Length > 0)
            {
                for (Int32 i = 0; i < Parameters.Length; i++)
                {
                    cmd.Parameters.Add(Parameters.GetValue(i));
                }
            }
            dt.Load(cmd.ExecuteReader(), LoadOption.OverwriteChanges);
        }
        return dt;
    }

执行此代码时,我收到一个InvalidCastException,其中说明了以下内容:

SqlParameterCollection 只接受非空的 SqlParameter 类型对象,不接受 String 对象。

代码掉线了:

cmd.Parameters.Add(Parameters.GetValue(i));

有什么想法吗?

感谢对上述代码的任何改进。


实际解决方案:

    private static readonly Regex regParameters = new Regex(@"@\w+", RegexOptions.Compiled);
    private static DataTable QueryImpl(ref DbConnection conn, String SqlToExecute, CommandType CommandType, Object[] Parameters)
    {
        SetupConnection(ref conn);
        DataTable dt = new DataTable();
        using (DbCommand cmd = conn.CreateCommand())
        {
            cmd.CommandText = SqlToExecute;
            cmd.CommandType = CommandType;
            if (Parameters != null && Parameters.Length > 0)
            {
                MatchCollection cmdParams = regParameters.Matches(cmd.CommandText);
                List<String> param = new List<String>();
                foreach (var el in cmdParams)
                {
                    if (!param.Contains(el.ToString()))
                    {
                        param.Add(el.ToString());
                    }
                }
                Int32 i = 0;
                IDbDataParameter dp;
                foreach (String el in param)
                {
                    dp = cmd.CreateParameter();
                    dp.ParameterName = el;
                    dp.Value = Parameters[i++];
                    cmd.Parameters.Add(dp);
                }
            }
            dt.Load(cmd.ExecuteReader(), LoadOption.OverwriteChanges);
        }
        return dt;
    } 

感谢您的想法/链接等:)

【问题讨论】:

  • Parameters.GetValue 有什么作用?
  • 不错的实际解决方案。但是,在 MS Access/OleDb 中将 DateTime.Now 设置为 DateTime 字段失败。
  • 我听说避免日期时间错误的解决方案是将毫秒设置为零,这将解决数据类型不匹配错误。真的吗? (我现在关心 MS Access 和 SQL Server)。

标签: c# datatable


【解决方案1】:

我相信 IDbCommand 有一个 CreateParameter() 方法:

var parameter = command.CreateParameter();
parameter.ParameterName = "@SomeName";
parameter.Value = 1;

command.Parameters.Add(parameter);

【讨论】:

    【解决方案2】:

    您可以将接受答案的代码添加到扩展方法中:

    public static class DbCommandExtensionMethods
    {
        public static void AddParameter (this IDbCommand command, string name, object value)
        {
            var parameter = command.CreateParameter();
            parameter.ParameterName = name;
            parameter.Value = value;
            command.Parameters.Add(parameter);
        }
    }
    

    【讨论】:

      【解决方案3】:

      我知道这不是您要的,但我可以提供更简单、更强大的解决方案。

      Microsoft Patterns and Practices 库包含一个功能强大且易于使用的数据访问应用程序块。下面是我们实际代码中执行存储过程并返回数据集的示例:

       object[] ParameterValues = new object[] {"1",DateTime.Now, 12, "Completed", txtNotes.Text};
       Database db = DatabaseFactory.CreateDatabase("ConnectionStringName");
       DataSet ds =  = db.ExecuteDataSet("StoredProcName", ParameterValues);
      

      Connection 是 OleDb、ODBC 等都没有关系。第一行代码中的 ConnectionStringName 只是 .config 文件中定义的 Consternating 的名称。您传入一个连接字符串名称、存储的过程名称和一个对象数组,它们构成了参数。 这只是众多可用的甜蜜功能之一。

      你会得到你想要构建的所有东西,然后是一些。

      官网在这里:http://msdn.microsoft.com/en-us/library/ff648951.aspx

      为了节省您的搜索时间,可在此处找到数据类文档:http://msdn.microsoft.com/en-us/library/microsoft.practices.enterpriselibrary.data(PandP.50).aspx

      (它从微软免费获得,并定期更新。)

      【讨论】:

        【解决方案4】:

        此答案的目的比您正在做的更具体,但在 @Dismissile 的答案的基础上,我使用 Dictionary 将参数名称和值提供给foreach 在我的个人项目中循环。

        using( IDbCommand dbCommand = dbConnection.CreateCommand() )
        {
            dbCommand.CommandText = Properties.Settings.Default.UpdateCommand;
            Dictionary<string,object> values = new Dictionary<string,object>()
            {
                {"@param1",this.Property1},
                {"@param2",this.Property2},
                // ...
            };
            foreach( var item in values )
            {
                var p = dbCommand.CreateParameter();
                p.ParameterName = item.Key;
                p.Value = item.Value;
                dbCommand.Parameters.Add(p);
            }
        }
        

        【讨论】:

          【解决方案5】:

          您的Parameters 参数必须是IDataParameter[] 类型,并且鉴于错误文本,具体实现需要是SqlParameter[] 类型。

          如果您希望保留您的签名,则需要一个工厂来派生必要的具体实现。

          【讨论】:

          • 老实说。从未使用过我所知道的工厂,这不会增加复杂性吗?你有工厂模式的例子吗?
          • @AustinSalonen 不使用IDataParameter[] 类型的参数不是问题的原因(尽管最好接受Array)。此外,您不需要工厂来创建正确的参数类型,如上所述,IDbCommand 有一个 CreateParameter 方法 - 我建议删除此答案。
          【解决方案6】:

          添加using System.Data.SqlClient;cmd.Parameters.Add(new SqlParameter("@parameterName", value));

          【讨论】:

          • -1'd,当其余代码明显使用 IDbConnection 时,您正在使用特定实现。这不是解决此问题的正确方法。
          猜你喜欢
          • 2012-08-19
          • 1970-01-01
          • 2013-01-23
          • 2013-08-18
          • 2011-06-03
          • 2014-02-01
          • 2021-12-28
          • 2011-04-06
          • 1970-01-01
          相关资源
          最近更新 更多