Подтвердить что ты не робот

Добавление параметров в IDbCommand

Я создаю небольшую вспомогательную функцию для возврата DataTable. Я хотел бы работать со всеми провайдерами, поддерживающими ADO.Net, поэтому я думал о том, чтобы использовать все IDbCommand или DbCommand, где это возможно.

Я достиг камнем преткновения со следующим кодом:

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

Спасибо за идеи/ссылки и т.д.:)

4b9b3361

Ответ 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 включает в себя блок приложений доступа к данным, который невероятно мощный и простой в использовании. Образец для выполнения хранимой процедуры и возврата набора данных показан ниже из нашего фактического кода:

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

Не имеет значения, является ли соединение OleDb, ODBC и т.д. ConnectionStringName в первой строке кода - это просто имя Consternating, как определено в файле .config. Вы передаете имя строки подключения, сохраненное имя proc и массив объектов, которые составляют параметры. Это всего лишь одна из многих доступных сладких функций.

Вы получите все, что вы пытаетесь построить, а затем некоторые.

Официальный сайт здесь: http://msdn.microsoft.com/en-us/library/ff648951.aspx

Чтобы сохранить некоторые поисковые запросы, документацию по классам данных можно найти здесь: http://msdn.microsoft.com/en-us/library/microsoft.practices.enterpriselibrary.data(PandP.50).aspx

(и он свободен от Microsoft и регулярно обновляется.)

Ответ 4

Ваш параметр Parameters должен иметь тип IDataParameter[] и, учитывая текст ошибки, конкретная реализация нуждается в типе SqlParameter[].

Если вы хотите сохранить свою подпись, вам понадобится factory, чтобы получить необходимую конкретную реализацию.

Ответ 5

Добавить using System.Data.SqlClient; и cmd.Parameters.Add(new SqlParameter("@parameterName", value));

Ответ 6

Этот ответ предназначен для немного более конкретной цели, чем то, что вы делаете, но основываясь на ответе @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);
    }
}