SqlParameter уже содержится в другой коллекции SqlParameterCollection-использует ли using() {} чит?


при использовании С помощью() {} (sic) блоки, как показано ниже, и предполагая, что cmd1 не живет за рамками первого С помощью() {} блок, почему второй блок должен выдавать исключение с сообщением 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);
        }
    }
}

Примечание: делаешь cmd1.Параметры.Очистить () непосредственно перед последней скобкой первого С помощью() {} блок избавит вас от исключения (а возможно, смущение).

Если вам нужно воспроизвести вы можете использовать следующие скрипты для создания объектов:

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
6 64

6 ответов:

Я подозреваю, что SqlParameter "знает", какая команда является частью, и что эта информация не очищается, когда команда удалена, но - это очищается при вызове command.Parameters.Clear().

лично я думаю, что я бы избежать повторного использования объектов в первую очередь, но это зависит от вас :)

использование блоков не гарантирует, что объект "уничтожен", просто что Dispose() метод называется. Что это на самом деле до конкретной реализации и в этом случае он явно не пустой коллекции. Идея состоит в том, чтобы обеспечить правильную утилизацию неуправляемых ресурсов, которые не будут очищены сборщиком мусора. Поскольку коллекция параметров не является неуправляемым ресурсом, это не совсем удивительно, что она не очищается методом dispose.

добавление cmd.Параметры.Очистить(); после выполнения должно быть нормально.

using определяет область, и делает автоматический вызов Dispose() за что мы любим его.

ссылка, выпадающая из области видимости, не заставит сам объект "исчезнуть", если другой объект имеет ссылку на него, что в этом случае будет иметь место для parameters имея ссылку на cmd1.

я столкнулся с этим исключением, потому что мне не удалось создать экземпляр объекта параметра. Я думал, что он жаловался на две процедуры, имеющие параметры с одинаковым именем. Он жаловался на то, что один и тот же параметр добавляется дважды.

            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.

я столкнулся с этой конкретной ошибкой, потому что я использовал одни и те же объекты SqlParameter как часть коллекции SqlParameter для вызова процедуры несколько раз. Причина этой ошибки IMHO заключается в том, что объекты SqlParameter связаны с определенной коллекцией SqlParameter, и вы не можете использовать те же объекты SqlParameter для создания новой коллекции SqlParameter.

, вместо -

var param1 = new SqlParameter{ DbType = DbType.Строка, ParameterName = param1, Direction = ParameterDirection.Input, Value =""};

ВАР параметр2 = новый объект sqlparameter{ тип dbtype = Типбд.Типа int64, Имяпараметра = параметр2, направление = ParameterDirection.Вход , Значение = 100};

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

ExecuteProc(sp_name, sqlParameter1);

/*ошибка :

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

ExecuteProc(sp_name, sqlParameter2);

*/

сделать это-

var param3 = новый SqlParameter{ DbType = DbType.Строка, ParameterName = param1, направление = ParameterDirection.Вход , значение = параметр1.Значение };

ВАР param4 = новый объект sqlparameter{ тип dbtype = Типбд.Типа int64, Имяпараметра = параметр2, направление = ParameterDirection.Вход, значение = param2.Значение};

SqlParameter[] sqlParameter3 = new[] { param3, param4 }; ExecuteProc(sp_name, sqlParameter3);