我使用单个参数调用此方法来调用我正在使用的存储过程,以查看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语句后关闭了,我尝试了但是把它拿回来了。我可以使用关闭一个我得到回复的东西。
答案 0 :(得分:1)
我认为这个问题是由于yield return
的使用造成的。在调用.First()
之前发生的调查员处理后,您的读者将被处置。
因此,当您在生成的[0]
上使用索引器IDataRecord
时,它会抛出异常,因为已经处理了返回的IDataRecord
(SqlDataReader
)。< / 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>
。