Bei der Verwendung der using() {}
(sic) -Blöcke (siehe unten) und der Annahme, dass cmd1
nicht den Rahmen des ersten using() {}
-Blocks überschreitet, sollte der zweite Block eine Ausnahme mit der Nachricht auslösen
Der SqlParameter ist bereits in einer anderen SqlParameterCollection enthalten
Bedeutet dies, dass Ressourcen und/oder Handles - einschließlich der an cmd1
angehängten Parameter (SqlParameterCollection
) - nicht freigegeben werden, wenn sie am Ende des Blocks zerstört werden?
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);
}
}
}
HINWEIS: Wenn Sie cmd1.Parameters.Clear () kurz vor der letzten Klammer des ersten using () {} - Blocks verwenden, werden Sie vor der Ausnahme (und möglicher Peinlichkeit) geschützt.
Wenn Sie reproduzieren müssen, können Sie die folgenden Skripts zum Erstellen der Objekte verwenden:
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
Ich vermute, dass SqlParameter
"weiß", zu welchem Befehl er gehört, und dass diese Informationen nicht gelöscht werden, wenn der Befehl gelöscht wird, aber ist , wenn Sie command.Parameters.Clear()
aufrufen.
Ich persönlich denke, ich würde die Wiederverwendung der Objekte vermeiden, aber es liegt an Ihnen :)
Durch die Verwendung von Blöcken kann nicht sichergestellt werden, dass ein Objekt "zerstört" wird, es wird lediglich die Dispose()
-Methode aufgerufen. Was dies tatsächlich tut, hängt von der konkreten Implementierung ab und in diesem Fall wird die Sammlung offensichtlich nicht entleert. Damit soll sichergestellt werden, dass nicht verwaltete Ressourcen, die nicht vom Garbage Collector entfernt werden, ordnungsgemäß entsorgt werden. Da die Parameters-Sammlung keine nicht verwaltete Ressource ist, ist sie nicht völlig überraschend. Sie wird von der dispose-Methode nicht gelöscht.
Hinzufügen von cmd.Parameters.Clear (); nach der Ausführung sollte es gut gehen.
using
definiert einen Gültigkeitsbereich und führt den automatischen Aufruf von Dispose()
aus, für den wir ihn lieben.
Ein außerhalb des Gültigkeitsbereichs liegender Verweis lässt das Objekt selbst nicht "verschwinden", wenn ein anderes Objekt einen Verweis darauf hat, was in diesem Fall der Fall ist, wenn parameters
einen Verweis auf cmd1
hat.
Ich habe auch das selbe Problem bekommen Danke @Jon, basierend darauf habe ich ein Beispiel gegeben.
Als ich die folgende Funktion aufgerufen habe, in der 2 mal der gleiche sqlparameter übergeben wurde. Im ersten Datenbankaufruf wurde es ordnungsgemäß aufgerufen, aber beim zweiten Mal wurde der obige Fehler ausgegeben.
public Claim GetClaim(long ClaimId)
{
string command = "SELECT * FROM tblClaim "
+ " WHERE RecordStatus = 1 and ClaimId = @ClaimId and ClientId [email protected]";
List<SqlParameter> objLSP_Proc = new List<SqlParameter>(){
new SqlParameter("@ClientId", SessionModel.ClientId),
new SqlParameter("@ClaimId", ClaimId)
};
DataTable dt = GetDataTable(command, objLSP_Proc);
if (dt.Rows.Count == 0)
{
return null;
}
List<Claim> list = TableToList(dt);
command = "SELECT * FROM tblClaimAttachment WHERE RecordStatus = 1 and ClaimId = @ClaimId and ClientId [email protected]";
DataTable dt = GetDataTable(command, objLSP_Proc); //gives error here, after add `sqlComm.Parameters.Clear();` in GetDataTable (below) function, the error resolved.
retClaim.Attachments = new ClaimAttachs().SelectMany(command, objLSP_Proc);
return retClaim;
}
Dies ist die gemeinsame DAL-Funktion
public DataTable GetDataTable(string strSql, List<SqlParameter> parameters)
{
DataTable dt = new DataTable();
try
{
using (SqlConnection connection = this.GetConnection())
{
SqlCommand sqlComm = new SqlCommand(strSql, connection);
if (parameters != null && parameters.Count > 0)
{
sqlComm.Parameters.AddRange(parameters.ToArray());
}
using (SqlDataAdapter da = new SqlDataAdapter())
{
da.SelectCommand = sqlComm;
da.Fill(dt);
}
sqlComm.Parameters.Clear(); //this added and error resolved
}
}
catch (Exception ex)
{
throw;
}
return dt;
}
Ich habe diesen besonderen Fehler festgestellt, weil ich dieselben SqlParameter-Objekte als Teil einer SqlParameter-Auflistung verwendet habe, um eine Prozedur mehrmals aufzurufen. Der Grund für diesen Fehler IMHO ist, dass die SqlParameter-Objekte einer bestimmten SqlParameter-Auflistung zugeordnet sind und Sie nicht die gleichen SqlParameter-Objekte zum Erstellen einer neuen SqlParameter-Auflistung verwenden können.
Also statt -
var param1 = neuer SqlParameter {DbType = DbType.String, ParameterName = Param1, Direction = ParameterDirection.Input, Value = ""};
var param2 = neuer SqlParameter {DbType = DbType.Int64, ParameterName = Parameter2, Direction = ParameterDirection.Input, Wert = 100};
SqlParameter [] sqlParameter1 = new [] {param1, param2};
ExecuteProc (sp_name, sqlParameter1);
/*ERROR :
SqlParameter [] sqlParameter2 = new [] {param1, param2};
ExecuteProc (sp_name, sqlParameter2);
* /
Mach das-
var param3 = neuer SqlParameter {DbType = DbType.String, ParameterName = param1, Direction = ParameterDirection.Input, Value = param1.Value};
var param4 = neuer SqlParameter {DbType = DbType.Int64, ParameterName = param2, Direction = ParameterDirection.Input, Value = param2.Value};
SqlParameter [] sqlParameter3 = new [] {param3, param4}; ExecuteProc (sp_name, sqlParameter3);
Problem
Ich habe eine gespeicherte SQL Server-Prozedur von C # ausgeführt, als ich auf dieses Problem gestoßen bin:
Ausnahmemeldung [SqlParameter ist bereits in einer anderen SqlParameterCollection enthalten.]
Ursache
Ich habe 3 Parameter an meine gespeicherte Prozedur übergeben. Ich habe das hinzugefügt
param = command.CreateParameter();
nur einmal insgesamt. Ich hätte diese Zeile für jeden Parameter hinzufügen sollen, dies bedeutet insgesamt dreimal.
DbCommand command = CreateCommand(ct.SourceServer, ct.SourceInstance, ct.SourceDatabase);
command.CommandType = CommandType.StoredProcedure;
command.CommandText = "[ETL].[pGenerateScriptToCreateIndex]";
DbParameter param = command.CreateParameter();
param.ParameterName = "@IndexTypeID";
param.DbType = DbType.Int16;
param.Value = 1;
command.Parameters.Add(param);
param = command.CreateParameter(); --This is the line I was missing
param.ParameterName = "@SchemaName";
param.DbType = DbType.String;
param.Value = ct.SourceSchema;
command.Parameters.Add(param);
param = command.CreateParameter(); --This is the line I was missing
param.ParameterName = "@TableName";
param.DbType = DbType.String;
param.Value = ct.SourceDataObjectName;
command.Parameters.Add(param);
dt = ExecuteSelectCommand(command);
Lösung
Hinzufügen der folgenden Codezeile für jeden Parameter
param = command.CreateParameter();
Diese Ausnahme ist aufgetreten, weil ein Parameterobjekt nicht instanziiert werden konnte. Ich dachte, es beschwerte sich über zwei Verfahren mit Parametern mit demselben Namen. Es wurde beschwert, dass derselbe Parameter zweimal hinzugefügt wurde.
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.