在SqlCommand中删除params

时间:2011-05-12 13:30:54

标签: c# tsql ado.net

我使用ADO.NET从DB中删除一些数据:

    using (SqlConnection conn = new SqlConnection(_connectionString))
    {
        try
        {
            conn.Open();

            using (SqlCommand cmd = new SqlCommand("Delete from Table where ID in (@idList);", conn))
            {
                cmd.Parameters.Add("@idList", System.Data.SqlDbType.VarChar, 100);
                cmd.Parameters["@idList"].Value = stratIds;

                cmd.CommandTimeout = 0;
                cmd.ExecuteNonQuery();
            }
        }
        catch (Exception e)
        {
            //_logger.LogMessage(eLogLevel.ERROR, DateTime.Now, e.ToString());
        }
        finally
        {
            conn.Close();
        }
    }

该代码在没有Exception的情况下执行,但数据未从DB中删除。 当我使用相同的算法插入或更新数据库时,一切正常。 有人知道这是什么问题吗?

3 个答案:

答案 0 :(得分:9)

您不能在常规TSQL中执行此操作,因为服务器会将@idList视为恰好包含逗号的单个值。但是,如果您使用List<int>,则可以使用dapper-dot-net和

connection.Execute("delete from Table where ID in @ids", new { ids=listOfIds });

dapper指出你的意思,并产生适当的参数化。

另一种选择是发送一个字符串并编写一个UDF来执行“拆分”操作,然后在查询中使用该UDF:

delete from Table where ID in (select Item from dbo.Split(@ids))

答案 1 :(得分:3)

根据Marc的Split-UDF,这是一个有效的实现:

CREATE FUNCTION [dbo].[Split]
(
    @ItemList NVARCHAR(MAX), 
    @delimiter CHAR(1)
)
RETURNS @IDTable TABLE (Item VARCHAR(50))  
AS      

BEGIN    
    DECLARE @tempItemList NVARCHAR(MAX)
    SET @tempItemList = @ItemList

    DECLARE @i INT    
    DECLARE @Item NVARCHAR(4000)

    SET @tempItemList = REPLACE (@tempItemList, ' ', '')
    SET @i = CHARINDEX(@delimiter, @tempItemList)

    WHILE (LEN(@tempItemList) > 0)
    BEGIN
        IF @i = 0
            SET @Item = @tempItemList
        ELSE
            SET @Item = LEFT(@tempItemList, @i - 1)
        INSERT INTO @IDTable(Item) VALUES(@Item)
        IF @i = 0
            SET @tempItemList = ''
        ELSE
            SET @tempItemList = RIGHT(@tempItemList, LEN(@tempItemList) - @i)
        SET @i = CHARINDEX(@delimiter, @tempItemList)
    END 
    RETURN
END  

这就是你怎么称呼它:

DELETE FROM Table WHERE (ID IN (SELECT Item FROM dbo.Split(@idList, ',')));

答案 2 :(得分:1)

我想更多地讨论这个问题。这似乎属于“如何获取多行数据到SQL ”的主题。在@Kate的情况下,她正在尝试DELETE-WHERE-IN,但是这个用户案例的有用策略与UPDATE-FROM-WHERE-IN或INSERT INTO-SELECT FROM的策略非常相似。我看到它的方式有几个基本策略。

字符串连接

这是最古老,最基本的方式。你做一个简单的“SELECT * FROM MyTable WHERE ID IN(”+ someCSVString +“);”

  • 超级简单
  • 让您自己接受SQL注入攻击的最简单方法。
  • 努力清理字符串最好花在其他解决方案上

对象映射器

正如@MarcGravell建议你可以使用像dapper-dot-net这样的东西,就像Linq-to-sql或Entity Framework一样。 Dapper让你connection.Execute("delete from MyTable where ID in @ids", new { ids=listOfIds });同样Linq可以让你做from t in MyTable where myIntArray.Contains( t.ID )

之类的事情
  • 对象映射器很棒。
  • 但是,如果您的项目是直接ADO,那么完成一项简单任务就是一个非常严重的变化。

CSV拆分

在此策略中,您将CSV字符串传递给SQL,无论是ad-hoc还是存储过程参数。该字符串由值为UDF的表处理,该值将值作为单个列表返回。

  • 自SQL-2000
  • 以来,这是一个成功的策略
  • @TimSchmelter给出了csv拆分功能的一个很好的例子。
  • 如果你谷歌这里有数百篇文章从各种字符串长度的基础知识到性能分析的各个方面。

表值参数

在SQL 2008中,可以定义自定义“表类型”。一旦定义了表类型,就可以在ADO中构造它并作为参数传递。

  • 这里的好处是它适用于更多场景而不仅仅是一个整数列表 - 它可以支持多列
  • 强类型
  • 将字符串处理拉回到一个非常好的图层/语言。
  • 这是一个相当大的主题,但SQL Server 2008 (ADO.NET)中的表值参数是一个很好的起点。