SqlParameter已经包含在另一个SqlParameterCollection中 - 使用(){}作弊吗?

Joh*_*ogo 76 .net c# sql-server ado.net

在使用using() {}如下所示的(sic)块时,并假设cmd1它不在第一个using() {}块的范围之外,为什么第二个块会抛出一个带有消息的异常

SqlParameter已包含在另一个SqlParameterCollection中

这是否意味着资源和/或句柄 - 包括SqlParameterCollection附加的参数() - cmd1在块的末尾被销毁时不会被释放?

using (var conn = new SqlConnection("Data Source=.;Initial Catalog=Test;Integrated Security=True"))
{
    var parameters = new SqlParameter[] { new SqlParameter("@ProductId", SqlDbType.Int ) };

    using(var cmd1 = new SqlCommand("SELECT ProductName FROM Products WHERE ProductId = @ProductId"))
    {
        foreach (var parameter in parameters)
        {
            cmd1.Parameters.Add(parameter);                
        }
        // cmd1.Parameters.Clear(); // uncomment to save your skin!
    }

    using (var cmd2 = new SqlCommand("SELECT Review FROM ProductReviews WHERE ProductId = @ProductId"))
    {
        foreach (var parameter in parameters)
        {
            cmd2.Parameters.Add(parameter);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

注意:在第一个using(){}块的最后一个大括号之前执行cmd1.Parameters.Clear()将使您免于异常(以及可能的尴尬).

如果需要重现,可以使用以下脚本创建对象:

CREATE TABLE Products
(
    ProductId int IDENTITY(1,1) NOT NULL PRIMARY KEY CLUSTERED,
    ProductName nvarchar(32) NOT NULL
)
GO

CREATE TABLE ProductReviews
(
    ReviewId int IDENTITY(1,1) NOT NULL PRIMARY KEY CLUSTERED,
    ProductId int NOT NULL,
    Review nvarchar(128) NOT NULL
)
GO
Run Code Online (Sandbox Code Playgroud)

Jon*_*eet 95

我怀疑SqlParameter"知道"它是哪一个命令,并且在处理命令时该信息不会被清除,但是在你打电话时会清除command.Parameters.Clear().

我个人认为我首先要避免重复使用这些对象,但这取决于你:)

  • 给别人的一张纸条.在退出第一个`using`块之前,我必须执行`Clear`.进入我的第二个"使用"块时执行此操作仍会引发此错误. (10认同)
  • 谢谢。我怀疑是这样。这也意味着 SqlParameter 将自己与一个已处理的对象相关联,我不确定这是一件好事 (2认同)

Ben*_*son 8

使用块不能确保对象被"销毁",只是Dispose()调用该方法.实际做的是取决于具体的实现,在这种情况下,它显然不会清空集合.我们的想法是确保垃圾收集器无法清理的非托管资源得到正确处理.由于Parameters集合不是非托管资源,因此dispose方法不会清除它并不令人惊讶.


小智 8

添加 cmd.Parameters.Clear(); 执行后应该没问题。


SaC*_*aCh 5

我遇到这个特殊错误是因为我使用相同的 SqlParameter 对象作为 SqlParameter 集合的一部分来多次调用过程。恕我直言,此错误的原因是 SqlParameter 对象与特定的 SqlParameter 集合关联,并且您不能使用相同的 SqlParameter 对象来创建新的 SqlParameter 集合。

所以,而不是这个:

var param1 = new SqlParameter{ DbType = DbType.String, ParameterName = param1,Direction = ParameterDirection.Input , Value = "" };
var param2 = new SqlParameter{ DbType = DbType.Int64, ParameterName = param2, Direction = ParameterDirection.Input , Value = 100};

SqlParameter[] sqlParameter1 = new[] { param1, param2 };

ExecuteProc(sp_name, sqlParameter1);

/*ERROR : 
SqlParameter[] sqlParameter2 = new[] { param1, param2 };
ExecuteProc(sp_name, sqlParameter2);
*/ 
Run Code Online (Sandbox Code Playgroud)

做这个:

var param3 = new SqlParameter{ DbType = DbType.String, ParameterName = param1, Direction = ParameterDirection.Input , Value = param1.Value };
var param4 = new SqlParameter{ DbType = DbType.Int64, ParameterName = param2, Direction = ParameterDirection.Input , Value = param2.Value};

SqlParameter[] sqlParameter3 = new[] { param3, param4 };

ExecuteProc(sp_name, sqlParameter3);
Run Code Online (Sandbox Code Playgroud)