You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C# WinForm报错:已有打开的DataReader关联命令,需先关闭

问题分析与解决:同一数据库连接下DataReader未关闭导致的错误

错误提示:"There is already an open DataReader associated with this Command which must be closed first"

原代码

MySqlConnection cn = conectar.fazer_conexao();
MySqlCommand cmd = new MySqlCommand();
cmd.Connection = cn;
try
{
    cn.Open();
    if (txt_codigo.Text == "")
    {
        cmd.CommandText = "Insert into operacoes (nome_cliente, codigo_cliente, data_locacao) VALUES ('" + cmb_cliente.Text + "','" + codigo_cliente.Text + "','" + Convert.ToDateTime(mask_dl.Text).ToString("yyyy/MM/dd") + "')";
    }

    cmd.CommandText = "SELECT 1544758";
    MySqlDataReader read = cmd.ExecuteReader();
    read.Read();

    int id = Convert.ToInt32(cmd.ExecuteScalar());

    for (int i = 0; i <= grid_jogos.RowCount - 1; i++)
    {
        if (Convert.ToBoolean(grid_jogos.Rows[i].Cells["select"].Value))
        {
            string jogos = grid_jogos.Rows[i].Cells[1].Value.ToString();
            cmd.CommandText = "Insert into itens (codigo_operacao, codigo_jogos) values ('" + id + "','" + jogos + "')";
        }
    }

    cmd.ExecuteNonQuery();
    cn.Close();
}

错误原因

  1. 未关闭DataReader就复用Command:创建MySqlDataReader后,没有调用read.Close()或用using包裹,就直接通过同一个cmd对象执行ExecuteScalar(),同一个Command不能同时关联打开的DataReader执行其他操作,这是报错的直接原因。
  2. 第一个Insert命令仅设置了CommandText,未执行就被SELECT语句覆盖,逻辑无效。
  3. 循环中仅更新CommandText,最后只执行一次ExecuteNonQuery(),只会插入最后一个选中的行,前面的操作全部被覆盖。
  4. 直接拼接字符串构造SQL,存在严重SQL注入风险。

修正方案

  1. 不需要DataReader的场景直接用ExecuteScalar()获取值,避免创建冗余的DataReader。
  2. 条件满足时执行第一个Insert命令。
  3. 循环中构造Insert命令后立即执行,避免覆盖操作。
  4. 使用using语句自动释放Connection、Command等资源,无需手动关闭。
  5. 改用参数化查询,杜绝SQL注入。

修正后的代码

// using自动管理连接资源,无需手动关闭
using (MySqlConnection cn = conectar.fazer_conexao())
{
    cn.Open();
    int id = 1544758; // 固定值直接赋值,无需额外查询

    // 执行operacoes表插入(如果条件满足)
    if (string.IsNullOrEmpty(txt_codigo.Text))
    {
        string insertOperacoesSql = "Insert into operacoes (nome_cliente, codigo_cliente, data_locacao) VALUES (@nome, @codigo, @data)";
        using (MySqlCommand cmdOperacoes = new MySqlCommand(insertOperacoesSql, cn))
        {
            cmdOperacoes.Parameters.AddWithValue("@nome", cmb_cliente.Text);
            cmdOperacoes.Parameters.AddWithValue("@codigo", codigo_cliente.Text);
            cmdOperacoes.Parameters.AddWithValue("@data", Convert.ToDateTime(mask_dl.Text));
            cmdOperacoes.ExecuteNonQuery();
        }
    }

    // 循环插入选中的itens数据
    string insertItensSql = "Insert into itens (codigo_operacao, codigo_jogos) values (@operacaoId, @jogoCodigo)";
    foreach (DataGridViewRow row in grid_jogos.Rows)
    {
        if (row.IsNewRow) continue; // 跳过表格自动生成的新行
        
        if (Convert.ToBoolean(row.Cells["select"].Value))
        {
            string jogoCodigo = row.Cells[1].Value.ToString();
            using (MySqlCommand cmdItens = new MySqlCommand(insertItensSql, cn))
            {
                cmdItens.Parameters.AddWithValue("@operacaoId", id);
                cmdItens.Parameters.AddWithValue("@jogoCodigo", jogoCodigo);
                cmdItens.ExecuteNonQuery();
            }
        }
    }
}

补充说明

同一数据库连接下可以执行多个操作,但需注意:

  • 同一个Command对象不能同时关联打开的DataReader,必须先关闭DataReader再复用。
  • 推荐为不同的SQL操作创建独立的Command对象,避免覆盖CommandText导致逻辑错误。
  • 参数化查询是必须的,绝不能直接拼接用户输入到SQL语句中。

内容的提问来源于stack exchange,提问作者user20990958

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 19:55:51