看看这个:
myReader = cmd.ExecuteReader();
if (myReader.HasRows)
{
while (myReader.Read())
{
info = myReader.GetString("info");
...
}
}
.....
好吧,我不知道为什么,但是当我编译并在另一台PC上使用它时,由于而,它会爆炸。但如果我这样做:
myReader = cmd.ExecuteReader();
if (myReader.HasRows)
{
if (myReader.Read()) <------------------- NOTICE THE IF
{
info = myReader.GetString("info");
...
}
}
.....
......会奏效。请注意,由于程序的逻辑,我知道每次都会只有一个元素。
可以这样做吗?它看起来很糟糕,也许不是一个好习惯(?)。我在问你的方向。
修改: 会发布更多代码,因为可以帮助我找到错误:
while (myReader.Read())
{
info = myReader.GetString("info");
...
/**
* Write the relevant info in the LOGS
*/
connection.Close(); <---------- :S
connection.Open(); <---------- if I don´t do this I got some problems with the connection!!!!
string queryLog = "INSERT INTO ....;
MySqlCommand cmdLog = new MySqlCommand(queryLog, connection);
cmdLog.ExecuteNonQuery();
}
答案 0 :(得分:13)
每当我只想要 一行 时,我都这样做,没有任何问题。
如果我期待单个值,我会改用ExecuteScalar
。这将只返回返回的结果集的第一行的第一列中保存的值,通常该集只有一列和一行,因此您不会注意到这一点。
此外,我倾向于不打扰if (myReader.HasRows)
,因为if (myReader.Read())
涵盖了这一点。
我不知道为什么while
会导致您发出问题...如果您不是if
,我只是提出我对while
使用{{1}}的看法。期待多行。
答案 1 :(得分:3)
在不使用while
的情况下,您无法检测到读者拥有的元素超出您认为的应有条件的意外情况。随着时间的推移,系统会发生变化,并且随着系统的发展,“读者只会有一个元素”等假设会变得不正确。
如果它对系统的功能或你所编写的代码的功能很重要,那么我仍然会使用while
并包含一些只调试构建的代码来断言你真的只收到一个元素。
答案 2 :(得分:3)
我认为if
的使用让你的代码的读者清楚地知道你只期望一个项目。您可以在结束后添加断言以捕获逻辑错误,如下所示:
if (myReader.Read()) {
info = myReader.GetString("info");
...
}
Debug.Assert(!myReader.Read(), "Reader has more elements than expected.");
答案 3 :(得分:3)
您确实可以使用if
,但您也可以在这种情况下使用while
而不会出现错误。只需将其更改为if
即可,但如果在可以有多行的情况下执行相同的操作,则会出现相同的错误。因此,重要的是要查看异常发生的原因。
让我们检查你的代码:
while (myReader.Read())
{
info = myReader.GetString("info");
...
到目前为止一切顺利。
/**
* Write the relevant info in the LOGS
*/
connection.Close(); <---------- :S
connection.Open(); <---------- if I don´t do this I got some problems with the connection!!!!
哦,呃!你已经解决了“一些问题”,但是你知道那些“一些问题”是什么吗?实际上你已经破坏了while
。
在我说“到目前为止这么好”的时候,这就是你发生的事情:
现在,根据IDbCommand.ExecuteReader
(http://msdn.microsoft.com/en-us/library/68etdec0.aspx)的规范,该读卡器正在使用该连接。除非关闭它,否则不允许对该连接执行任何操作,直到您在阅读器上显式或通过Close()
致电Dispose()
,如果在{{1}中分配了阅读器,则会发生这种情况。阻止。
现在,严格来说并非总是如此。总是允许给定的实现提供超过接口承诺(无论是根据接口签名还是根据文档)。一旦using
返回false(我曾经实现过的唯一一个),许多实现将“释放”连接以便重用,SQLServer 2005有一个Read()
选项,允许同一连接同时支持多个datareader立刻(有缺点)。尽管如此,除了这些规则的松动之外,我们现在唯一可以解决的问题是调用MultipleActiveResultSets=True
。
出于这个原因,当您尝试调用Close()
时,您会以错误消息的形式出现“某些问题”,因为您尝试使用其他用途的连接。
所以,你通过对连接做的唯一事情 - 关闭它 - 然后再次打开它来“修复”这个。无论出于何种目的,你都会有一个全新的联系!
现在,当您循环回cmdLog.ExecuteNonQuery()
时,它再次调用while
。此方法从来自连接的数据流中读取,并返回false(如果没有更多结果)或根据从该流中读取的内容创建一组字段。
但它没有,因为你关闭了那个连接。所以它“爆炸”有一个例外,因为你试图从一个封闭的连接中读取,而这是无法完成的。
现在,当您使用myReader.Read()
替换此while
时,您再也没有回到已被破坏的if
操作,因此代码再次运行。
但如果您需要使用包含多行的结果集,那么您要做什么?
您可以使用MARS。请参阅http://msdn.microsoft.com/en-us/library/h32h3abf%28v=vs.80%29.aspx。坦率地说,除非事情从中得到更多,否则我会避免它;它有一些微妙的含义,如果你碰到它们可能会让人感到困惑。
您可以推迟下一次操作,直到关闭读者群。在这种情况下,通过取出不必要的Read()
和Open()
,这只是一个小小的节省:
Close()
现在,拥有两个连接而不是一个连接似乎很浪费。但是:
using(myReader = cmd.ExecuteReader())
{
while(myReader.Read())
{
string info = myReader.GetString("info");
/* Do stuff */
using(SqlConnection logConn = new SqlConnection(...))
{
logConn.Open();
string queryLog = "INSERT INTO ....;
MySqlCommand cmdLog = new MySqlCommand(queryLog, connection);
cmdLog.ExecuteNonQuery();
}
}
}
,我们就会将其重新发布到池中,因此如果在很多线程中有很多这种情况发生,那么移动中的连接总数可能会少于线程数的两倍。另一方面,如果只有一个线程这样做,那么只有一个额外的连接,所以谁在乎。总之,如果不重用它就不能使用连接,这是一个彻头彻尾的错误。通常,一次不能在同一连接上进行多个操作。使用SQLServer2005的ExecuteNonQuery()
选项可以实现这一点,尽管它有复杂性。通常,如果您希望一次执行多个DB事务,则应使用多个连接。
所有这一切,你仍然可以使用MultipleActiveResultSets
而不是if
,但这样做是因为它是当时有意义的,而不是修复你不理解的错误并拥有它<{1}}无法选择的时候回来。
答案 4 :(得分:1)
您是否妥善处理了连接和阅读器?使用Using
,例如:
using (myReader = cmd.ExecuteReader())
{
if (myReader.HasRows)
{
while (myReader.Read())
{
info = myReader.GetString("info");
...
}
}
}
答案 5 :(得分:0)
我认为你应该仍然使用while,即使你只期望一行,然后在你调用它时使用linq来表达单行期望。您可以使用协程来表达这一点。
public IEnumerable<string> GetInfo()
{
// make command and reader...
while(reader.Read()
{
yield return reader.GetString("info");
}
}
然后调用者应该使用Single()方法来表达只有一行的期望。
var info = GetInfo().Single();
答案 6 :(得分:-5)
此代码应添加以下内容以使其返回或不返回行
myReader = cmd.ExecuteReader();
myReader.Read();
if (myReader.HasRows)
{
while (myReader.Read())
{
info = myReader.GetString("info");
}
}