所以我在ADO.NET中运行一个查询,我知道它返回一行。我的代码的相关部分如下:
SqlCommand sqc = new SqlCommand();
sqc.Connection = new SqlConnection("connection string");
sqc.CommandText = "SELECT A, B FROM C WHERE D=@d";
sqc.Parameters.AddWithValue("@d", "d");
sqc.Connection.Open();
SqlDataReader rdr = sqc.ExecuteReader();
bool boolio = rdr.Read();
String a = (String)rdr["A"];
当我运行这个时,我在最后一行得到一个例外,抱怨我正在尝试读取没有数据的地方。
当我在VS中逐步执行此操作时,我在rdr.Read()行执行之前检查rdr,我可以看到我想要的数据位于阅读器中。然后我调用rdr.Read(),结果为FALSE,表示没有更多数据供我阅读。当我再次检查rdr时,内部ResultsView为空。
我意识到我可以通过放弃对Read()的调用来获取我的数据但是:这种行为与明确说明“SqlDataReader的默认位置在第一条记录之前的MSDN documentation相反。”因此,你必须调用Read才能开始访问任何数据。“这也与我在网上找到的每个SqlDataReader用法示例相反,例如this SO question,这似乎只是为了嘲讽我。
请注意,我已经针对.NET 3.5和.NET 4.5测试了我的代码,结果相同。
我错过了什么吗? ADO.NET中是否有错误?任何意见都表示赞赏!
更新1: 我在最后一行得到的实际例外是:
System.Data.dll中出现未处理的“System.InvalidOperationException”类型异常
附加信息:没有数据时读取的尝试无效。
更新2:
由于Nathan Skerl无法重现此行为,并且发布了经过验证的工作代码,后来对我失败了,我怀疑我们正在运行的平台可能存在问题。为了记录,我使用的是Windows 7 Professional(64位)Service Pack 1,并且针对.NET Framework 3.5和4.5编译了我的项目并获得了相同的结果。如果有任何相关信息我没有提供,请告诉我,我会添加。
答案 0 :(得分:2)
更新:经过一些故障排除后,由于通过展开结果视图(调用Read()
并消耗行)检查调试器中的阅读器,我们意识到阅读器是空的。 / p>
使用你的代码我在Linqpad中运行了这个单元测试,结果如预期的那样,初始的reader.read()前进到“ONE”行,第二次调用行“TWO”。你能用这样的测试重现你的错误:
SqlCommand sqc = new SqlCommand();
sqc.Connection = (SqlConnection)this.Connection;
sqc.CommandText = "SELECT 'ONE' [A] union all select 'TWO' order by [A] asc;";
sqc.Parameters.AddWithValue("@d", "d");
sqc.Connection.Open();
SqlDataReader rdr = sqc.ExecuteReader();
bool boolio = rdr.Read();
String a = (String)rdr["A"];
a.Dump();
rdr.Read();
String b = (String)rdr["A"];
b.Dump();
您能否告诉我们这种模式的回归:
using (SqlConnection connection = (SqlConnection)this.Connection)
using (SqlCommand sqc = new SqlCommand("select 'ONE' as [A] union all select 'TWO';", connection))
{
connection.Open();
using (SqlDataReader rdr = sqc.ExecuteReader())
{
while (rdr.Read())
{
Console.WriteLine(String.Format("{0}", (String)rdr["A"]));
}
}
}
答案 1 :(得分:0)
我遇到了一个完全相同的问题,尝试从SP返回1行,从Microsoft Dynamics 2013R2使用ADO SQLCommand调用。
具体来说,我使用这个C / AL代码来调用我的SP:
SQLCommand := SQLCommand.SqlCommand();
SQLCommand.CommandText := 'Custom_Item_Card_report_Get_Item_Qties'; //name of SP
SQLCommand.Connection := SQLConnection;
SQLCommand.CommandType := SQLCommand.CommandType.StoredProcedure;
SQLCommand.CommandTimeout := 0;
IF SQLCommand.Parameters.Count = 0 THEN BEGIN
SQLCommand.Parameters.AddWithValue('@CompanyName', COMPANYNAME);
SQLCommand.Parameters.AddWithValue('@ItemNo', InputItemCode);
SQLCommand.Parameters.AddWithValue('@FromDate', InputDateFrom);
SQLCommand.Parameters.AddWithValue('@Location', InputLocation);
END;
SQLReader := SQLCommand.ExecuteReader;
//IF SQLReader.Read() THEN BEGIN
rs1QtyCumulative := SQLReader.Item('QtyCumulative');
MESSAGE(FORMAT(rs1QtyCumulative));
//END;
现在,在我的结果集中,我只有2行(十三列三列)。第0行和第1行,让我们调用它们。
如本期所述,如果没有IF附件,它会向我发送来自SP结果集的第1行,第1列数据的消息。
使用 IF和.Read(),它会给出一个错误,指出在不存在的情况下发出了读取数据的命令。它引用了MESSAGE之前的代码行。
SQLReader.Item('QtyCumulative');
正如本期所述,这与文档相矛盾,该文档明确指出 .ExecuteReader() 将保留 SQLReader 集合在执行后指向之前>>数据开始的行
这肯定不会发生,最重要的是,如果我们在调用之后立即调用SQLReader对象的 .Read()方法。 ExecuteReader()然后它将移动到结果集的第二个行。
显然,他们对 SqlDataReader 对象进行了一些调试。