You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

C#操作MySQL数据库遇System.InvalidCastException异常求解决

解决C#操作MySQL时System.InvalidCastException异常问题

看起来你遇到的System.InvalidCastException问题主要出在ExecuteScalar()的强制转换和资源管理上,咱们一步步来排查修复:

先分析原代码的核心问题

你的CheckRows方法存在几个关键问题,直接导致了转换异常和资源泄漏:

  1. 未处理ExecuteScalar()的空返回:当查询没有匹配行时,ExecuteScalar()会返回null(或DBNull.Value),直接用(Int32)强制转换会触发转换异常。
  2. 资源释放语句永远不会执行return read;之后的cmd.Dispose();closeConnection();完全不会被执行,会导致数据库连接和命令对象无法正常释放,长期运行会引发连接池耗尽问题。
  3. 异常捕获不完整:仅捕获了openConnection()的异常,ExecuteScalar()执行时的SQL错误、权限问题等异常都未被处理。

修复方案

1. 重构CheckRows方法,安全处理转换并释放资源

推荐用using语句自动管理MySqlCommand资源(它实现了IDisposable接口),同时用安全转换替代强制转换,再通过finally块确保连接关闭:

public int CheckRows(string query)
{
    int rowCount = 0;
    try
    {
        openConnection();
        // using块会自动在结束时释放cmd资源
        using (MySqlCommand cmd = new MySqlCommand(query, con))
        {
            object queryResult = cmd.ExecuteScalar();
            
            // 处理null/DBNull的情况,同时安全转换为int
            if (queryResult != null && queryResult != DBNull.Value)
            {
                int.TryParse(queryResult.ToString(), out rowCount);
            }
        }
    }
    catch (MySqlException ex)
    {
        MessageBox.Show($"数据库操作出错: {ex.Message}");
    }
    catch (Exception ex)
    {
        MessageBox.Show($"未知错误: {ex.Message}");
    }
    finally
    {
        // 无论是否异常,都确保关闭连接
        closeConnection();
    }
    return rowCount;
}

2. 确保查询语句返回可转换为int的结果

按钮事件中的查询语句要使用COUNT(*)来统计行数,而不是直接查询某一列。比如检查发票是否存在的正确查询应该是:

string qry = $"SELECT COUNT(*) FROM your_invoice_table WHERE invoice_id = {invoice}";

如果直接写SELECT invoice_id FROM ... WHERE ... LIMIT 1,无匹配行时会返回null,再次触发转换异常。

3. 改用参数化查询避免SQL注入(重要)

虽然你现在转换了int类型,但直接拼接SQL仍有风险,养成参数化查询的习惯更安全。可以重载CheckRows方法支持参数:

// 重载方法,支持参数化查询
public int CheckRows(string query, params MySqlParameter[] parameters)
{
    int rowCount = 0;
    try
    {
        openConnection();
        using (MySqlCommand cmd = new MySqlCommand(query, con))
        {
            cmd.Parameters.AddRange(parameters);
            object queryResult = cmd.ExecuteScalar();
            
            if (queryResult != null && queryResult != DBNull.Value)
            {
                int.TryParse(queryResult.ToString(), out rowCount);
            }
        }
    }
    catch (MySqlException ex)
    {
        MessageBox.Show($"数据库操作出错: {ex.Message}");
    }
    catch (Exception ex)
    {
        MessageBox.Show($"未知错误: {ex.Message}");
    }
    finally
    {
        closeConnection();
    }
    return rowCount;
}

然后在按钮事件中这样调用:

private void button2_Click(object sender, EventArgs e)
{
    // 先验证输入是否为有效整数
    if (!int.TryParse(textBox9.Text, out int invoice))
    {
        MessageBox.Show("请输入有效的发票编号!");
        return;
    }

    // 参数化查询语句
    string qry = "SELECT COUNT(*) FROM your_invoice_table WHERE invoice_id = @InvoiceId";
    // 创建参数
    MySqlParameter param = new MySqlParameter("@InvoiceId", MySqlDbType.Int32) { Value = invoice };
    // 调用重载后的方法
    int existingRows = CheckRows(qry, param);

    // 根据结果做后续处理
    if (existingRows > 0)
    {
        MessageBox.Show("该发票已存在!");
    }
    else
    {
        MessageBox.Show("该发票不存在!");
    }
}

验证效果

这样修改后,无论查询是否有匹配行,都不会触发InvalidCastException,同时数据库资源能正确释放,还彻底避免了SQL注入风险。

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

火山引擎 最新活动