WPF TextBox输入Double/Float存MySQL异常与输入限制解决方案
问题背景
应用内设置两个文本框,分别用于配置儿童票、成人票价格。文本框内容变更时会触发textbox_ValueChanged事件,执行priceChanged()方法将价格写入MySQL数据库,存储价格的字段类型为double。
输入整数时功能运行正常,输入浮点数时出现两类异常:
- 按顺序输入"5"、","、"5"时:输入第二个"5"后程序立即崩溃,崩溃位置为数据库执行代码
cmd.ExecuteNonQuery();,报错信息:
Data truncated for column 'adults' at row 1
- 按顺序输入"5"、"."、"5"时:程序无崩溃,但存入数据库的数值会丢失小数点,例如输入"5.5"实际存储为"55"。
原有数据库保存代码如下:
public static void updatePrice(double _adults, double _children) { MySqlConnection cnn = OpenCnn(); MySqlCommand cmd = new MySqlCommand("UPDATE price SET adults = '" + _adults + "', children = '" + _children + "';", cnn); cmd.ExecuteNonQuery(); }
原有调用逻辑代码如下:
private void priceChanged() { double adultPrice; double childPrice; try { adultPrice = Convert.ToDouble(adultPriceTextbox.Text); } catch { adultPrice = 0.0; } try { childPrice = Convert.ToDouble(childPriceTextbox.Text); } catch { childPrice = 0.0; } DatabaseInterface.updatePrice(adultPrice, childPrice); }
补充运行环境说明:程序部署在德国区域,当地小数书写默认使用,作为分隔符,而非.。需求为实现支持整数、浮点数输入的价格文本框,同时增加输入屏蔽,禁止输入字母类字符,仅允许输入数字、.、,符号。
问题根因
- 数据库操作采用字符串拼接SQL的写法,未使用参数化查询:德国区域下double类型转字符串默认以
,作为小数分隔符,拼接进SQL语句后,MySQL会将逗号识别为字段值分隔符,直接触发值截断报错;如果用户输入.作为小数分隔符,不符合本地默认格式规则,转换时会直接忽略小数点,导致5.5被识别为55存入数据库。 - 文本框未做输入校验与过滤,未对用户输入的两种小数分隔符做统一兼容处理。
- 数值转换未显式指定区域文化规则,默认依赖系统区域配置,遇到非默认分隔符时转换逻辑异常,且用try-catch做转换判断性能较差。
实现方案
1. 输入屏蔽与自动兼容
给两个价格文本框绑定统一的KeyPress事件,仅允许输入数字、控制字符(退格等)、单个小数分隔符,同时自动将用户输入的.替换为德国区域默认的,,兼容不同输入习惯:
// 窗体初始化时绑定事件 adultPriceTextbox.KeyPress += PriceTextBox_KeyPress; childPriceTextbox.KeyPress += PriceTextBox_KeyPress; private void PriceTextBox_KeyPress(object sender, KeyPressEventArgs e) { TextBox targetTb = sender as TextBox; // 允许数字、控制字符输入 if (char.IsControl(e.KeyChar) || char.IsDigit(e.KeyChar)) { e.Handled = false; return; } // 仅允许输入一个小数分隔符,自动统一为逗号适配德国区域格式 if ((e.KeyChar == ',' || e.KeyChar == '.') && !targetTb.Text.Contains(',') && !targetTb.Text.Contains('.')) { e.KeyChar = ','; e.Handled = false; return; } // 其余字符全部拦截 e.Handled = true; }
2. 修正数值解析逻辑
使用double.TryParse显式指定德国区域文化做数值转换,相比try-catch性能更高,同时预处理输入内容,进一步兼容分隔符输入场景:
private void priceChanged() { CultureInfo deCulture = new CultureInfo("de-DE"); double adultPrice = 0.0; double childPrice = 0.0; // 二次兼容:把输入中残留的点替换为逗号,避免解析异常 string adultInput = adultPriceTextbox.Text.Trim().Replace('.', ','); string childInput = childPriceTextbox.Text.Trim().Replace('.', ','); double.TryParse(adultInput, NumberStyles.Float, deCulture, out adultPrice); double.TryParse(childInput, NumberStyles.Float, deCulture, out childPrice); DatabaseInterface.updatePrice(adultPrice, childPrice); }
3. 数据库层改用参数化查询(核心修复)
彻底替换字符串拼接的SQL写法,通过参数传值,由数据库驱动直接处理double类型,不存在字符串格式不匹配问题,同时可避免SQL注入风险:
public static void updatePrice(double _adults, double _children) { // using语句自动释放连接资源,避免连接泄漏 using (MySqlConnection cnn = OpenCnn()) { string updateSql = "UPDATE price SET adults = @adults, children = @children;"; using (MySqlCommand cmd = new MySqlCommand(updateSql, cnn)) { // 参数直接传入double类型值,无需手动转字符串 cmd.Parameters.AddWithValue("@adults", _adults); cmd.Parameters.AddWithValue("@children", _children); cmd.ExecuteNonQuery(); } } }
内容的提问来源于stack exchange,提问作者Jannes
相关产品推荐
相关产品推荐

