El SqlParameter ya está contenido en otra SqlParameterCollection – ¿Usa trampas using () {}?

Mientras usa los bloques using () {} (sic) como se muestra a continuación, y suponiendo que cmd1 no vive más allá del scope del primer bloque using () {} , ¿por qué debería el segundo bloque lanzar una excepción con el mensaje The SqlParameter is ya está contenido en otra SqlParameterCollection ? ¿Significa que los recursos y / o identificadores (incluidos los parámetros (SqlParameterCollection)) asociados a cmd1 no se liberan cuando se destruyen al final del bloque?

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); } } } 

NOTA: Hacer cmd1.Parameters.Clear () justo antes del último paréntesis del primer bloque using () {} lo salvará de la excepción (y posible vergüenza).

Si necesita reproducirse, puede usar los siguientes scripts para crear los objetos:

 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 

Sospecho que SqlParameter “sabe” de qué comando es parte, y que esa información no se borra cuando se elimina el comando, pero se borra al llamar a command.Parameters.Clear() .

Personalmente, creo que evitaría volver a utilizar los objetos en primer lugar, pero depende de ti 🙂

El uso de bloques no garantiza que un objeto sea “destruido”, simplemente que se llama al método Dispose() . Lo que realmente hace depende de la implementación específica y, en este caso, no vacía la colección. La idea es garantizar que los recursos no administrados que no serían limpiados por el recolector de basura sean desechados correctamente. Como la colección Parameters no es un recurso no administrado, no es del todo sorprendente, no se borra con el método de eliminación.

Añadiendo cmd.Parameters.Clear (); después de la ejecución debería estar bien.

using define un scope, y hace la llamada automática de Dispose() por la que nos encanta.

Una referencia que caiga fuera del scope no hará que el objeto en sí “desaparezca” si otro objeto tiene una referencia al mismo, que en este caso será el caso para los parameters tienen una referencia a cmd1 .

Encontré esta excepción porque no pude crear una instancia de un objeto de parámetro. Pensé que se quejaba de dos procedimientos con parámetros con el mismo nombre. Se quejaba de que se agregara el mismo parámetro dos veces.

  Dim aParm As New SqlParameter() aParm.ParameterName = "NAR_ID" : aParm.Value = hfCurrentNAR_ID.Value m_daNetworkAccess.UpdateCommand.Parameters.Add(aParm) aParm = New SqlParameter Dim tbxDriveFile As TextBox = gvNetworkFileAccess.Rows(index).FindControl("tbxDriveFolderFile") aParm.ParameterName = "DriveFolderFile" : aParm.Value = tbxDriveFile.Text m_daNetworkAccess.UpdateCommand.Parameters.Add(aParm) **aParm = New SqlParameter()** <--This line was missing. Dim aDDL As DropDownList = gvNetworkFileAccess.Rows(index).FindControl("ddlFileAccess") aParm.ParameterName = "AccessGranted" : aParm.Value = aDDL.Text **m_daNetworkAccess.UpdateCommand.Parameters.Add(aParm)** <-- The error occurred here. 

Me enfrenté a este error en particular porque estaba usando los mismos objetos SqlParameter como parte de una colección SqlParameter para invocar un procedimiento varias veces. El motivo de este error en mi humilde opinión es que los objetos SqlParameter están asociados a una determinada colección SqlParameter y no puede usar los mismos objetos SqlParameter para crear una nueva colección SqlParameter.

Entonces, en lugar de –

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);

* /

Hacer esto-

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);