SqlDataReader.Read不能像广告一样工作?

时间:2013-05-21 22:39:46

标签: sql-server ado.net sqldatareader

所以我在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编译了我的项目并获得了相同的结果。如果有任何相关信息我没有提供,请告诉我,我会添加。

2 个答案:

答案 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 对象进行了一些调试。