Можно ли отправить коллекцию идентификаторов в качестве параметра ADO.NET SQL?
Вопрос
Например.могу ли я написать что-то вроде этого кода:
public void InactiveCustomers(IEnumerable<Guid> customerIDs)
{
//...
myAdoCommand.CommandText =
"UPDATE Customer SET Active = 0 WHERE CustomerID in (@CustomerIDs)";
myAdoCommand.Parameters["@CustomerIDs"].Value = customerIDs;
//...
}
Единственный известный мне способ — присоединиться к моему IEnumerable, а затем использовать конкатенацию строк для построения строки SQL.
Решение
Обычно способ сделать это заключается в передаче списка значений, разделенных запятыми, и внутри вашей хранимой процедуры проанализировать список и вставить его во временную таблицу, которую затем можно использовать для соединений.По состоянию на SQL-сервер 2005, это стандартная практика работы с параметрами, которые должны содержать массивы.
Вот хорошая статья о различных способах решения этой проблемы:
Передача списка/массива в хранимую процедуру SQL Server
Но для SQL-сервер 2008, мы, наконец, сможем передавать табличные переменные в процедуры, сначала определив таблицу как пользовательский тип.
Хорошее описание этого (и других функций 2008 года) есть в этой статье:
Введение в новые возможности программирования T-SQL в SQL Server 2008
Другие советы
Вы можете с SQL 2008.Он вышел не так давно, но доступен.
Как было упомянуто в комментарии, Эрланд Соммарског написал серию статей на эту тему (ссылка на них приведена ниже).Статьи очень подробные и могут служить справочным материалом.Хотя некоторые из упомянутых методов специфичны для SQL Server (T-SQL), они также могут работать и для других СУБД (например, использование XML
тип данных):
Массивы и списки в SQL Server 2008 с использованием параметров с табличным значением:
- Табличные параметры (TVP)
Массивы и списки в SQL Server 2005 и более поздних версиях, когда TVP не помогают:
- строковая сериализация и десериализация скалярных значений
- SQLCLR
- передача данных структурированного списка через тип данных XML
- Динамический SQL
Вы можете использовать тип параметра xml:
CREATE PROCEDURE SelectByIdList(@productIds xml) AS
DECLARE @Products TABLE (ID int)
INSERT INTO @Products (ID) SELECT ParamValues.ID.value('.','VARCHAR(20)')
FROM @productIds.nodes('/Products/id') as ParamValues(ID)
SELECT * FROM
Products
INNER JOIN
@Products p
ON Products.ProductID = p.ID
Неа.Параметры подобны значениям SQL, подчиняясь первая нормальная форма, по сути, он может быть только один...
Как вы, наверное, знаете, генерация строк SQL — рискованное дело:ты оставляешь себя открытым для SQL-инъекция атаки.Пока вы имеете дело с добросовестными GUID, с вами все будет в порядке, но в противном случае вам нужно обязательно очистить введенные данные.
Вы не можете передать список как один параметр SQl.Вы можете string.Join(',') GUIDS, например "0000-0000-0000-0000, 1111-1111-1111-1111", но это будет сильно нагружать базу данных и на самом деле неоптимально.И вам нужно передать всю строку как один составной динамический оператор, вы не можете добавить ее в качестве параметра.
Вопрос:
Откуда вы берете список идентификаторов неактивных клиентов?
Я предлагаю подойти к проблеме немного по-другому.Переместите всю эту логику в базу данных, например:
Create procedure usp_DeactivateCustomers
@inactive varchar(50) /*or whatever values are required to identify inactive customers*/
AS
UPDATE Customer SET c.Active = 0
FROM Customer c JOIN tableB b ON c.CustomerID = b.CustomerID
WHERE b.someField = @inactive
И вызовите это как хранимую процедуру:
public void InactiveCustomers(string inactive)
{
//...
myAdoCommand.CommandText =
"usp_DeactivateCustomers";
myAdoCommand.Parameters["@inactive"].Value = inactive;
//...
}
Если в базе данных существует список GUID, зачем мне:Найди их;поместите их в общий список;развернуть список в переменную CSV/XML/Table, просто чтобы снова представить их обратно в БД?????Они уже там!Я что-то пропустил?