是否可以将ID的集合作为ADO.NET SQL参数发送?

时间:2020-03-06 14:32:13  来源:igfitidea点击:

例如。我可以写这样的代码:

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值,基本上,只能有一个...

如我们所知,生成SQL字符串是有风险的业务:我们容易遭受SQL注入攻击。只要我们使用的是真正的GUID,就可以了,但是否则,我们必须确保清除输入内容。

我们不能将列表作为单个SQl参数传递。我们可以使用string.Join(',')这样的GUIDS,例如" 0000-0000-0000-0000,1111-1111-1111-1111",但这会增加数据库开销,并且实际上不是最佳选择。而且我们必须将整个字符串作为单个串联的动态语句传递,我们不能将其添加为参数。

问题:

我们从哪里获得代表不活跃客户的ID列表?

我的建议是以不同的方式解决这个问题。将所有逻辑移到数据库中,例如:

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变量,只是将它们再次呈现给数据库?他们已经在那里!我想念什么吗?

通常,执行此操作的方法是传入用逗号分隔的值列表,然后在存储过程中解析该列表并将其插入到临时表中,然后可将其用于联接。从Sql Server 2005开始,这是处理需要保存数组的参数的标准做法。

这是一篇有关解决此问题的各种方法的好文章:

将列表/数组传递给SQL Server存储过程

但是对于Sql Server 2008,我们首先通过将表定义为自定义类型,最终将表变量传递给过程。

本文对此(以及更多2008功能)进行了很好的描述:

SQL Server 2008中新的T-SQL可编程性功能简介

我们可以使用SQL2008. 它还没有发布很长时间,但是已经可以使用。

我们可以使用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

http://weblogs.asp.net/jgalloway/archive/2007/02/16/passing-lists-to-sql-server-2005-with-xml-parameters.aspx