program tip

SqlParameter는 이미 다른 SqlParameterCollection에 포함되어 있습니다. using () {} 치트를 사용합니까?

radiobox 2020. 10. 17. 10:19
반응형

SqlParameter는 이미 다른 SqlParameterCollection에 포함되어 있습니다. using () {} 치트를 사용합니까?


은 USING 동안 using() {}아래와 같이 (SiC)를 차단하고, 그 가정 cmd1제의 범위를 넘어 살지 않는 using() {}블록, 제 2 블록 이유는 메시지가 예외를 발생한다

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

참고 : 첫 번째 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

나는 용의자 SqlParameter의 그것의 부분을 명령하고, 그 정보는 명령이 배치이지만, 경우 삭제되지 않도록하는 "인식" 되는 전화 할 때 지워 command.Parameters.Clear().

개인적으로 나는 처음에 객체를 재사용하는 것을 피할 것이라고 생각하지만 그것은 당신에게 달려 있습니다 :)


블록을 사용한다고해서 객체가 "파괴"되는 것은 아니며 단순히 Dispose()메서드가 호출 된다는 것 입니다. 실제로하는 일은 특정 구현에 달려 있으며이 경우 컬렉션을 비우지 않습니다. 아이디어는 가비지 수집기에 의해 정리되지 않는 관리되지 않는 리소스가 올바르게 삭제되도록하는 것입니다. Parameters 컬렉션은 관리되지 않는 리소스가 아니기 때문에 dispose 메서드에 의해 지워지지 않는다고 전적으로 의심하지 않습니다.


cmd.Parameters.Clear (); 추가 실행 후 괜찮을 것입니다.


using범위를 정의하고 Dispose()우리가 좋아 하는 자동 호출을 수행 합니다.

범위를 벗어난 참조는 다른 개체에 참조가있는 경우 개체 자체가 "사라지지"않습니다.이 경우 참조가있는 경우가 parameters됩니다 cmd1.


나는 또한 내가 예제를 준 것에 근거하여 @Jon에게 감사드립니다.

동일한 sqlparameter가 두 번 전달 된 아래 함수를 호출했을 때. 첫 번째 데이터베이스 호출에서는 제대로 호출되었지만 두 번째에서는 위의 오류가 발생했습니다.

    public Claim GetClaim(long ClaimId)
    {
        string command = "SELECT * FROM tblClaim "
            + " WHERE RecordStatus = 1 and ClaimId = @ClaimId and ClientId =@ClientId";
        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 =@ClientId";

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

이것은 일반적인 DAL 기능입니다.

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

I faced this particular error because I was using the same SqlParameter objects as part of a SqlParameter collection for calling a procedure multiple times. The reason for this error IMHO is that the SqlParameter objects are associated to a particular SqlParameter Collection and you can't use the same SqlParameter objects to create a new SqlParameter collection.

So, instead of -

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

*/

Do this-

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


I encountered this exception because I had failed to instantiate a parameter object. I thought it was complaining about two procedures having parameters with the same name. It was complaining about the same parameter being added twice.

            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.

Issue
I was executing a SQL Server stored procedure from C# when I encountered this issue:

Exception message [The SqlParameter is already contained by another SqlParameterCollection.]

Cause
I was passing 3 parameters to my stored procedure. I added the

param = command.CreateParameter();

only once altogether. I should have added this line for each parameter, it means 3 times altogether.

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

Solution
Adding the following line of code for each parameter

param = command.CreateParameter();

참고URL : https://stackoverflow.com/questions/7837762/the-sqlparameter-is-already-contained-by-another-sqlparametercollection-does-u

반응형