点击DataGridView单元格读取数据到TextBox时出现读取器已关闭错误
解决「Invalid attempt to call Read when reader is closed」错误
我来帮你搞定这个问题!这个错误的核心原因是你的SqlDataReader在尝试读取数据之前就被意外关闭了,再加上代码里还有几个容易引发问题的细节,咱们一步步来修正:
问题分析
- 全局资源未正确管理:你使用了全局的
SqlCommand和SqlConnection对象,这类对象如果被重复使用且没有正确清理状态,很容易出现连接/读取器状态异常的情况。 - 缺少资源自动释放机制:没有用
using语句包裹数据库相关对象,它们的生命周期无法被自动管理,可能导致连接泄漏或者读取器被提前关闭。 - SQL注入风险:直接把
dataGridView的单元格值拼接到SQL语句里,这是非常危险的操作,容易被恶意利用。 - 未处理边界情况:没有判断
dataGridView2是否有选中行,直接访问SelectedRows[0]会引发索引越界异常。
修复后的代码
private void dataGridView2_CellClick(object sender, DataGridViewCellEventArgs e) { // 先判断是否有选中的行 if (dataGridView2.SelectedRows.Count == 0) return; // 获取选中行的id_subdiss值 var subDissId = dataGridView2.SelectedRows[0].Cells[0].Value; if (subDissId == DBNull.Value || subDissId == null) return; // 使用using语句自动管理连接、命令、读取器的生命周期 using (SqlConnection cn = new SqlConnection("你的数据库连接字符串")) using (SqlCommand cmd = new SqlCommand("select * from subdiseases where id_subdiss = @SubDissId", cn)) { // 添加参数,避免SQL注入 cmd.Parameters.AddWithValue("@SubDissId", subDissId); cn.Open(); using (SqlDataReader dr4 = cmd.ExecuteReader()) { // 读取数据前先判断是否有结果 if (dr4.Read()) { a = dr4["id_diss"].ToString(); comboBox1.Text = dr4["name_diss"].ToString(); namesub.Text = dr4["name_subdiss"].ToString(); namedet.Text = dr4["details"].ToString(); } } // 读取器会在这里自动关闭 } // 命令和连接会在这里自动关闭 }
关键改进点
- 使用
using语句:确保SqlConnection、SqlCommand、SqlDataReader在使用完毕后自动释放资源,避免状态异常和资源泄漏。 - 参数化查询:用
@SubDissId参数代替直接拼接字符串,彻底消除SQL注入风险。 - 边界情况处理:先检查是否有选中行、单元格值是否有效,避免不必要的异常。
- 避免全局数据库对象:每次操作创建新的连接和命令对象,保证状态干净。
内容的提问来源于stack exchange,提问作者ah medo
相关产品推荐
相关产品推荐

