Как перевести List<string> в SqlParameter для оператора Sql In?
Я, кажется, смущен тем, как выполнить In
заявление с SqlParameter
, Пока у меня есть следующий код:
cmd.CommandText = "Select dscr from system_settings where setting in @settings";
cmd.Connection = conn;
cmd.Parameters.Add(new SqlParameter("@settings", settingList));
reader = cmd.ExecuteReader();
settingsList
это List<string>
, когда cmd.ExecuteReader()
называется, я получаю ArgumentException
из-за невозможности отобразить List<string>
на "известный тип провайдера".
Как (безопасно) выполнить In
запрос с SqlCommand
s?
6 ответов
Вы можете попробовать что-то вроде этого:
string sql = "SELECT dscr FROM system_settings WHERE setting IN ({0})";
string[] paramArray = settingList.Select((x, i) => "@settings" + i).ToArray();
cmd.CommandText = string.Format(sql, string.Join(",", paramArray));
for (int i = 0; i < settingList.Count; ++i)
{
cmd.Parameters.Add(new SqlParameter("@settings" + i, settingList[i]));
}
Вы, кажется, пытаетесь передать многозначный параметр, этот синтаксис SQL не будет выполнять то, что вы ожидаете. Вы можете передать параметр табличного значения.
Читать это: http://www.sommarskog.se/arrays-in-sql.html
в частности: http://www.sommarskog.se/arrays-in-sql-2008.html
private static void datatable_example() {
string [] custids = {"ALFKI", "BONAP", "CACTU", "FRANK"};
DataTable custid_list = new DataTable();
custid_list.Columns.Add("custid", typeof(String));
foreach (string custid in custids) {
DataRow dr = custid_list.NewRow();
dr["custid"] = custid;
custid_list.Rows.Add(dr);
}
using(SqlConnection cn = setup_connection()) {
using(SqlCommand cmd = cn.CreateCommand()) {
cmd.CommandText =
@"SELECT C.CustomerID, C.CompanyName
FROM Northwind.dbo.Customers C
WHERE C.CustomerID IN (SELECT id.custid FROM @custids id)";
cmd.CommandType = CommandType.Text;
cmd.Parameters.Add("@custids", SqlDbType.Structured);
cmd.Parameters["@custids"].Direction = ParameterDirection.Input;
cmd.Parameters["@custids"].TypeName = "custid_list_tbltype";
cmd.Parameters["@custids"].Value = custid_list;
using (SqlDataAdapter da = new SqlDataAdapter(cmd))
using (DataSet ds = new DataSet()) {
da.Fill(ds);
PrintDataSet(ds);
}
}
}
}
Если вы используете Sql Server 2008 или более позднюю версию, вы можете использовать параметры с табличными значениями - это позволяет вам передавать таблицу значений в качестве параметра. Из.net вы определяете "структурированный" тип SqlParameter и устанавливаете значение в то, что реализует IEnumerable.
См. Полный справочник MSDN с примерами здесь: http://msdn.microsoft.com/en-us/library/bb675163.aspx
Я всегда использую свою собственную функцию для создания таких параметров:
public void SomeDataFunction() {
ArrayList params = GetParameters(someEntity);
CommandObject.Parameters.AddRange(parameters.ToArray());
}
public static ArrayList GetParameters(ISomeEntity entity) {
ArrayList result = new ArrayList {
OleDbUtility.NewDbParam("@Param1", OleDbType.Integer, , entity.Parameter1),
OleDbUtility.NewDbParam("@Param2", OleDbType.VarChar, 9, entity.Parameter2),
}
}
public static OleDbParameter NewDbParam(string parameterName, OleDbType dataType,
int size, object value) {
OleDbParameter result = new OleDbParameter(parameterName, dataType, size, string.Empty);
result.Value = value;
return result;
}
Используйте XML, это достаточно быстро для этого сценария. Вы бы превратили свой список в XML и просто передали строку:
CREATE TABLE #myTempTable
( Letter VARCHAR(20) )
INSERT INTO #myTempTable (Letter) VALUES ('A'), ('B')
Declare @xml XML = '<a>A</a><a>B</a><a>C</a>'
Select * from #myTempTable
Where Letter in
(Select p.value('.', 'VARCHAR(40)') AS [Letter] from @xml.nodes('//a') as t(p))
DROP TABLE #myTempTable
Обычно я передаю список в виде строки, разделенной запятыми, а затем использую табличную функцию, чтобы "разбить" строку на таблицу, которую затем можно использовать для соединения в другом запросе.
DECLARE @Settings TABLE (Sid INT)
INSERT INTO @Settings(Sid)
SELECT CAST(Items AS INT) FROM dbo.Split(@SettingsParameter, ',')
Если, конечно, вы не используете SQL Server 2008, я бы использовал параметры с табличным значением.