使用SqlDbReader方法获得的收益在读取器关闭时无效尝试调用CheckDataIsReady。例外

时间:2014-03-19 13:04:35

标签: c#

我使用单个参数调用此方法来调用我正在使用的存储过程,以查看yield是否对我的团队有益。

这是调用存储过程的通用方法。对它的调用工作正常,

var parameters = new List<SqlParameter>();
parameters.Add(CreateParamter("GL45", "@prefix", SqlDbType.VarChar));
var reader = StoreProcedureReader("Yield", parameters.ToArray());

这将返回我需要的读者,但是下一行

string value = reader.First()[0].ToString();

导致激活,读取器关闭时无效尝试调用CheckDataIsReady。

 public static IEnumerable<IDataRecord> StoreProcedureReader(String StoredProcedureName, SqlParameter[] paramters)
    {
        using (var conn = new SqlConnection(MyConnectionString))
        {
            using (var cmd = new SqlCommand(StoredProcedureName, conn))
            {
                cmd.CommandType = CommandType.StoredProcedure;
                cmd.Parameters.AddRange(paramters);
                conn.Open();
                using (var reader = cmd.ExecuteReader())
                {
                    while (reader.Read())
                    {
                        yield return reader;
                    }                        
                }
            }
        }
    } 

我在StackOverflow上看了几个示例,似乎我可能错过了一些东西,一个例子在sqlCommand using语句后关闭了,我尝试了但是把它拿回来了。我可以使用关闭一个我得到回复的东西。

1 个答案:

答案 0 :(得分:1)

我认为这个问题是由于yield return的使用造成的。在调用.First()之前发生的调查员处理后,您的读者将被处置。

因此,当您在生成的[0]上使用索引器IDataRecord时,它会抛出异常,因为已经处理了返回的IDataRecordSqlDataReader)。< / p>

您最好的选择可能是填写并复制读者的结果,并确保在阅读器被处理之前检索结果,即

public static IEnumerable<IList<object>> StoreProcedureReader(String StoredProcedureName, SqlParameter[] paramters)
{
    using (var conn = new SqlConnection(MyConnectionString))
    {
        using (var cmd = new SqlCommand(StoredProcedureName, conn))
        {
            cmd.CommandType = CommandType.StoredProcedure;
            cmd.Parameters.AddRange(paramters);
            conn.Open();
            using (var reader = cmd.ExecuteReader())
            {
                while (reader.Read())
                {
                    var fieldCount = reader.FieldCount;
                    var results = new object[fieldCount];
                    for(var i = 0; i < fieldCount; ++i)
                    {
                        results[i] = reader[i];
                    }
                    yield return results;
                }                        
            }
        }
    }
} 

请注意IEnumerable<IList<object>>的返回类型,您的调用代码不需要更改。

这的缺点是所有数据都被读入内存。避免这种情况的另一个选项是手动控制生成的IEnumerator<T>,因此使用原始代码,请执行以下操作:

using(var enumerator = reader.GetEnumerator())
{
    // Move to first
    if(!enumerator.MoveNext())
        throw new NotImplementedException();
    var value = enumerator.Current[0].ToString();
}

这将确保在您阅读了您感兴趣的值之前,不会处理生成的IEnumerator<T>