В моем тестовом проекте у меня есть статический класс FixtureSetup, который я использую для настройки данных интеграционного тестирования на валидацию.
Я использую одну и ту же переменную SqlCommand и SqlParameter (не сам объект) внутри этого класса, многократно, снова и снова используя одни и те же ссылки на переменные, каждый раз назначая новые объекты SqlCommand и SqlParameter. Само мое соединение создается один раз и передается в методы, выполняющие настройку, поэтому каждая настройка использует свою собственную отдельную ссылку на соединение, и хотя одно и то же соединение используется несколько раз, оно всегда в линейной последовательности.
В одном из таких методов я столкнулся с очень странной ситуацией, когда моя переменная SqlCommand, похоже, просто устала.
cmd = new SqlCommand("INSERT INTO Subscription (User_ID, Name, Active) VALUES (@User_ID, @Name, @Active)", conn);
parameter = new SqlParameter("@User_ID", TestUserID); cmd.Parameters.Add(parameter);
parameter = new SqlParameter("@Name", "TestSubscription"); cmd.Parameters.Add(parameter);
parameter = new SqlParameter("@Active", true); cmd.Parameters.Add(parameter);
cmd.ExecuteNonQuery();
cmd = new SqlCommand("SELECT Subscription_ID FROM [Subscription] WHERE Name = 'TestSubscription'", conn);
parameter = new SqlParameter("@User_ID", TestUserID);
cmd.Parameters.Add(parameter);
using (dr = cmd.ExecuteReader())
{
while (dr.Read())
{
TestSubscriptionID = dr.GetInt32(dr.GetOrdinal("Subscription_ID"));
}
}
cmd = new SqlCommand("INSERT INTO SubscriptionCompany (Subscription_ID, Company_ID) VALUES (@Subscription_ID, @Company_ID)", conn);
parameter = new SqlParameter("@Subscription_ID", TestSubscriptionID); cmd.Parameters.Add(parameter);
parameter = new SqlParameter("@Company_ID", KnownCompanyId); cmd.Parameters.Add(parameter);
cmd.ExecuteNonQuery();
В приведенном выше примере, в последней строке, выполняя то же самое, что я сделал буквально в десятках других мест (вставьте данные, прочитайте столбец идентификатора и запишите их), я получу следующее:
SetUp: System.InvalidOperationException: ExecuteNonQuery требует
открытое и доступное соединение. Текущее состояние соединения
закрыто. в
System.Data.SqlClient.SqlConnection.GetOpenConnection (метод String)
НО - замените cmd новой переменной myCmd, и все работает плавно!
SqlCommand myCmd;
myCmd = new SqlCommand("INSERT INTO Subscription (User_ID, Name, Active) VALUES (@User_ID, @Name, @Active)", conn);
parameter = new SqlParameter("@User_ID", TestUserID); myCmd.Parameters.Add(parameter);
parameter = new SqlParameter("@Name", "TestSubscription"); myCmd.Parameters.Add(parameter);
parameter = new SqlParameter("@Active", true); myCmd.Parameters.Add(parameter);
myCmd.ExecuteNonQuery();
myCmd = new SqlCommand("SELECT Subscription_ID FROM [Subscription] WHERE Name = 'TestSubscription'", conn);
parameter = new SqlParameter("@User_ID", TestUserID);
myCmd.Parameters.Add(parameter);
using (dr = myCmd.ExecuteReader())
{
while (dr.Read())
{
TestSubscriptionID = dr.GetInt32(dr.GetOrdinal("Subscription_ID"));
}
}
myCmd = new SqlCommand("INSERT INTO SubscriptionCompany (Subscription_ID, Company_ID) VALUES (@Subscription_ID, @Company_ID)", conn);
parameter = new SqlParameter("@Subscription_ID", TestSubscriptionID); myCmd.Parameters.Add(parameter);
parameter = new SqlParameter("@Company_ID", KnownCompanyId); myCmd.Parameters.Add(parameter);
myCmd.ExecuteNonQuery();
Какого черта здесь происходит? Моя команда var просто устала ???
Что подсказало мне «исправление», так это то, что я заметил в своей трассировке, что в моем блоке «чтение идентификатора» мой блок cmd.Parameters содержал только ОДИН параметр, добавлялся второй, и когда я принудительно заставлял первый cmd.Parameters.Добавить строку для повторного выполнения, количество параметров в списке упало до 0. Вот что побудило меня попробовать метод уровня SqlCommand ... потому что у меня была сумасшедшая идея, что мой cmd устал ... Представьте, что я шок, когда я, видимо, оказался прав!
Редактировать: Здесь я не перерабатываю никакие объекты - просто ссылку на переменную (статическая SqlCommand на уровне класса). Приношу свои извинения за раннюю путаницу в моей формулировке вопроса.