Ответ 1
Я считаю, что IDbCommand имеет метод CreateParameter():
var parameter = command.CreateParameter();
parameter.ParameterName = "@SomeName";
parameter.Value = 1;
command.Parameters.Add(parameter);
Я создаю небольшую вспомогательную функцию для возврата 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;
}
Спасибо за идеи/ссылки и т.д.:)
Я считаю, что IDbCommand имеет метод CreateParameter():
var parameter = command.CreateParameter();
parameter.ParameterName = "@SomeName";
parameter.Value = 1;
command.Parameters.Add(parameter);
Вы можете добавить код принятого ответа к методу расширения:
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);
}
}
Я знаю, что это не то, о чем вы просите, но у меня есть гораздо более простое и надежное решение.
Библиотека шаблонов и практик 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 и регулярно обновляется.)
Ваш параметр Parameters
должен иметь тип IDataParameter[]
и, учитывая текст ошибки, конкретная реализация нуждается в типе SqlParameter[]
.
Если вы хотите сохранить свою подпись, вам понадобится factory, чтобы получить необходимую конкретную реализацию.
Добавить using System.Data.SqlClient;
и
cmd.Parameters.Add(new SqlParameter("@parameterName", value));
Этот ответ предназначен для немного более конкретной цели, чем то, что вы делаете, но основываясь на ответе @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);
}
}