[c#] 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;
        }


답변

프로 시저를 여러 번 호출하기 위해 SqlParameter 컬렉션의 일부로 동일한 SqlParameter 개체를 사용했기 때문에이 특정 오류가 발생했습니다. 이 IMHO 오류의 이유는 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);
*/

이 작업을 수행:

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


답변

매개 변수 개체를 인스턴스화하지 못했기 때문에이 예외가 발생했습니다. 같은 이름의 매개 변수를 가진 두 개의 프로 시저에 대해 불평하고 있다고 생각했습니다. 동일한 매개 변수가 두 번 추가되는 것에 대해 불평했습니다.

            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.