我的SqlCommand变量是否工作过度?它累了吗

本文关键字:SqlCommand 变量 是否 工作 我的 | 更新日期: 2023-09-27 18:29:08

在我的测试项目中,我有一个名为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();

在上面显示的最后一行,我在其他几十个地方做了同样的事情(插入数据,读取ID列并捕获它),得到了以下内容:

SetUp:System.InvalidOperationException:ExecuteNonQuery需要打开且可用的连接。连接的当前状态为关闭在System.Data.SqlClient.SqlConnection.GetOpenConnection(字符串方法)

但是-用新变量myCmd替换cmd,一切都很顺利!

        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只是累了吗???

让我知道"修复"的是,我在追踪中注意到,在我的"读取id"块中,我的cmd。参数块中只有一个参数,第二个添加了,当我强制执行第一个cmd时。参数。添加行以再次执行,列表中的参数数降至0。这就是促使我尝试方法级SqlCommand的原因。。。因为我有一个疯狂的想法,我的cmd累了。。。想象一下,当我显然是对的时候,我的震惊!

编辑:我在这里不回收任何对象,只回收变量引用本身(类级别的静态SqlCommand)。我对早先我对这个问题措辞上的混乱表示歉意。

我的SqlCommand变量是否工作过度?它累了吗

每个查询使用一个命令并调用dispose(或者更好的是,包装在using语句中)。你不想"重用"ado.net组件。

大编辑:

发件人:http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqldatareader.close.aspx

完成使用时,必须显式调用Close方法SqlDataReader将关联的SqlConnection用于任何其他目的

Close方法填充输出参数的值,返回值和记录受到影响,增加了关闭所需的时间用于处理大型或复杂查询的SqlDataReader。当返回值和受查询影响的记录数不重要,关闭SqlDataReader所需的时间可以通过调用关联的的Cancel方法来减少SqlCommand对象,然后调用Close方法。

所以试试:

using (dr = cmd.ExecuteReader())
{
    while (dr.Read())
    {
        TestSubscriptionID = dr.GetInt32(dr.GetOrdinal("Subscription_ID"));
    }
    dr.Close();
}

检查您是否没有将DataReader设置为CommandBehavior.CloseConnection,因为您提到您正在使用连接进行测试初始化。

此外,DataReader确实占用资源,因此请使用Dispose

您真的需要在每次尝试后创建一个新的连接对象吗?

myCmd = new SqlCommand(...)
//your code
myCmd = new SqlCommand(...)
//etc

你可以说:

myCmd.CommandText = "INSERT INTO SubscriptionCompany (Subscription_ID, Company_ID) VALUES (@Subscription_ID, @Company_ID)";

以便您可以重用您的命令对象。此外,您还可以在每次调用后重置参数。只需致电myCmd.Parameters.Clear()即可。

此外,请确保将SqlCommand封装在using语句中,以便正确清理它们。

using (SqlCommand cmd = new SqlCommand())
{
    cmd.CommandText = "some proc"
    cmd.Connection = conn;
    //set params, get data, etc
    cmd.CommandText = "another proc"
    cmd.Parameters.Clear();
    //set params, get date, etc.
}