【发布时间】:2026-02-15 14:35:02
【问题描述】:
这是我的服务器端代码,它正在执行 SQL 存储过程并向我发送一些表结果。
public IEnumerable<IDataRecord> SomeFuncToCallDB(string pName, SqlParameter[] sqlParams, int commandTimeout = -1)
{
using (SqlConnection cn = GetNewConnection())
using (SqlCommand cmd = cn.CreateCommand())
{
cmd.CommandText = pName;
cmd.CommandType = CommandType.StoredProcedure;
if (commandTimeout != -1) cmd.CommandTimeout = commandTimeout;
if (sqlParams.Length > 0)
{
FixNullParams(sqlParams);
cmd.Parameters.AddRange(sqlParams);
}
cn.Open();
using (SqlDataReader dr = cmd.ExecuteReader())
{
while (dr.Read())
{
yield return (IDataRecord)dr;
}
cn.Close();
}
}
}
这里是 FixNullParams 函数。
private void FixNullParams(SqlParameter[] parameters)
{
foreach (SqlParameter p in parameters) if (p.Value == null) p.Value = DBNull.Value;
}
什么时候,我这样调用这个函数,
List<SqlParameter> parameters = new List<SqlParameter>();
parameters.Add(new SqlParameter("@AgencyFilter", "CountyPool"));
IEnumerable<IDataRecord> dataFromDB = salesTax.SomeFuncToCallDB("[Data].[uspSomeSQLProc]", parameters.ToArray());
我得到以下异常。
“SqlParameter 已被另一个 SqlParameterCollection 包含。”
这发生在 cmd.Parameters.AddRange 行。
同时,如果我这样调用同一个函数,
List<SqlParameter> parameters = new List<SqlParameter>();
parameters.Add(new SqlParameter("@AgencyFilter", "CountyPool"));
//IEnumerable<IDataRecord> dataFromDB = salesTax.SomeFuncToCallDB("[Data].[uspAgenciesSelect]", parameters.ToArray());
foreach (IDataRecord eachRec in salesTax.SomeFuncToCallDB("[Data].[uspSomeSQLProc]", parameters.ToArray()))
{
int x = eachRec.FieldCount;
}
然后它工作正常并循环遍历每条记录。
这是我的问题。
- 调用此过程的正确方法是什么?
- 如何在后面的调用中没有失败,但在前面的调用中失败了?
- 如果我必须为此函数编写单元测试,我只想获取 IEnumerable,然后断言记录数。但看起来,由于这个异常,我不能做这种测试。那么对这个函数进行单元测试的正确方法是什么?
【问题讨论】:
-
那么你在哪里创建
parameters?大概您正在使用已在其他地方使用的参数。请澄清您的问题,编辑代码部分,使它们尽可能易读(而不是缩进很长的一段距离),并在每个帖子中提出 一个 问题。 -
可枚举的方法在编译时会生成一个状态机。我不能告诉你细节,但我认为这与它有关。如果有人知道那是 Jon Skeet。
-
@JonSkeet 我相信你是对的,OP 没有描述他的代码中包含问题的部分,只描述了错误被捕获的地方。我们需要您说明 SQL 参数类实例的位置和使用情况。 OP 正在重用一个 sql 参数。也许您使用的“FixNull”方法提供了相同的“空”参数,或者它返回的任何参数,这会使系统感到困惑,但老实说,我们无法通过您提供的代码确定错误的原因。
-
我在代码中添加了缺失的信息。只是想知道呼叫如何以一种方式工作而以另一种方式失败。希望能学到新东西。
-
迭代器方法的主体在 foreach 迭代之前不会进入,所以我很难相信只做第一个 sn-p 中显示的操作会抛出,而第二个不会。第二个必须执行与第一个相同的所有代码,然后执行一些。在您再次显示使用
parameters的位置之后,是否发生了什么事?
标签: c# .net ienumerable yield