C# 数据读取器在while循环中的连接上打开,尽管已明确关闭
已存在与此命令关联的打开的DataReader 必须先关闭它 好的。所以我们在这方面做了大量的数据库读取,足以证明一个通用函数可以简化它。我刚刚更改了它,这样当使用活动连接调用时,该函数不再关闭连接,因为无论哪种方式,它都是一行。在这样做的过程中,我发现了这个bug。在C# 数据读取器在while循环中的连接上打开,尽管已明确关闭,c#,C#,已存在与此命令关联的打开的DataReader 必须先关闭它 好的。所以我们在这方面做了大量的数据库读取,足以证明一个通用函数可以简化它。我刚刚更改了它,这样当使用活动连接调用时,该函数不再关闭连接,因为无论哪种方式,它都是一行。在这样做的过程中,我发现了这个bug。在while循环的第二次迭代中,DBRead函数在尝试实际执行时将得到一个错误,并根据上述错误进行抱怨。 然而在每次迭代结束时,都有一个reader.Close()调用,没有任何条件 现在。。。我已经做了一些调查,发现了一些关于使用
while
循环的第二次迭代中,DBRead函数在尝试实际执行时将得到一个错误,并根据上述错误进行抱怨。
然而在每次迭代结束时,都有一个reader.Close()调用,没有任何条件
现在。。。我已经做了一些调查,发现了一些关于使用的东西。。。老实说,我不知道我会怎么做(我想我可以很快找到答案),但我不知道它是否能解决问题
我读到的每一个问题实际上都没有结束。而在这种情况下,我想我是在读卡器上为每一个打开调用一个close,然后在之后重用连接。我错了多少
// Find all the unprocessed gifts in the inhouse table.
SQL = "SELECT * FROM ToREgift WHERE processed = 0";
ReadCommand.Connection = ReadConnect;
ReadCommand.CommandText = SQL;
dbRERead = ReadCommand.ExecuteReader();
while (dbRERead.Read()) // Loop through them.
{
RowId = Convert.ToInt32(dbRERead["id"].ToString());
// Lookup the RE ConstituentId from the ToREConstituent table.
string ToREConstituent_Id = dbRERead["ToREConstituent_id"].ToString();
Reader = FunctionsClass.DBRead(vars.Catalog, "SELECT Constituent_Id FROM ToREConstituent WHERE ID = " + ToREConstituent_Id.ToString(), ref Connection);
Reader.Read();
string ConstituentId = Reader["Constituent_Id"].ToString();
bool UseRG = false;
try
{
UseRG = Convert.ToBoolean(dbRERead["Use_RG"]);
}
catch (Exception ex) { }
;
if (!UseRG)
{
if (dbRERead["TypeOfGift"].ToString() == "RecGiftPC")
{
UseRG = true;
}
}
AddSingleGift(ConstituentId, UseRG, RowId);
SQL = "SELECT Constituent_Id FROM ToREConstituent WHERE Id = " + ToREConstituent_Id;
dbRECommand.CommandText = SQL;
Reader = dbRECommand.ExecuteReader();
while (Reader.Read())
{
ConstituentId = Reader["Constituent_Id"].ToString();
}
Reader.Close();
}
dbRERead.Close();
--
public static SqlDataReader DBRead(string DB, string SQL, ref SqlConnection Connection)
{
SqlDataReader functionReturnValue = null;
// !! IMPORTANT !!
// This will initialise and open a connection as needed.
// The caller is responsible for closing the connection
if(Connection==null)
{
Connection = new SqlConnection();
}
if(Connection.ConnectionString=="")
{
Connection.ConnectionString = "Data Source = REDEV;Initial Catalog = " + DB + ";Integrated Security = True";
}
try
{
Connection.Open();
}
catch (Exception ex)
{
if(ex.Message!="The connection was not closed. The connection's current state is open.")
{
throw ex;
}
// Else continue, because if that's the error, doesn't matter, just move on.
}
SqlCommand dbCommand = new SqlCommand();
dbCommand.Connection = Connection;
dbCommand.CommandType = System.Data.CommandType.Text;
dbCommand.CommandText = SQL;
dbCommand.CommandTimeout = 0;
try {
functionReturnValue = dbCommand.ExecuteReader();
return functionReturnValue;
} catch (Exception ex) {
//frmMain.BatchError = true;
System.Windows.Forms.MessageBox.Show("Error reading Database. Can't Continue, sorry. Debug information below:" + vars.vbCrLf + vars.vbCrLf + ex.Message + vars.vbCrLf + SQL + vars.vbCrLf + vars.vbCrLf + Connection.ConnectionString);
Connection.Close();
System.Environment.Exit(0);
}
return functionReturnValue;
// Cleanup
//dbCommand = Nothing
}
请在那里做一个大的重构,每个问题都会消失。清空catch
块,捕获Exception
并检查精确的本地化消息(忽略所有其他内容)。根本不使用。在一个方法中创建连接,并让它在另一个方法中关闭(没有任何使用块),当其他人阅读它时,可能会令人惊讶<代码>变量vbCrlf
?为什么不Environment.NewLine
<代码>while(reader.Read())
当您只需要一条记录时。没有参数构建的SQL代码(SQL注入呢?)。顺便说一句,你们在哪里关闭连接?!您也没有在DBRead
中处理DBCommand
,我想仔细看看还会发现一些其他的东西,但我认为是时候重写这几行了。尝试一些简单的规则:1)当类实现了IDisposable
时,您必须使用using
。2) 不要捕捉异常(除非你有很好的理由),而是捕捉你所需要的。3) 尽量使您的功能尽可能小(只执行一项任务,每项任务)。4) 不要连接字符串以生成SQL命令:使用参数。我同意。当前状态下的代码坏了,坏了,坏了。扔掉它,重新开始。好的。无论如何,我现在采取了一种完全不同的方法,因为我们通过一种变通方法(将读取器传递到DBRead函数)修复了它,并回到了真正的问题,即temprecords由于某种原因总是空的。所以,抛开一切,做一些不同的事情。我还是会考虑你建议的东西。另外,Environment
并不总是存在,而我们定义的vars.VbCrLf
确实存在。(当然,它不是VB,但我们从转换的代码开始。还没有看到更改名称的理由。)