C# 基于JSON数组动态翻转SQL Server SelectedType表bit字段值的实现方法
问题解答
1. 翻转bit类型值的SQL逻辑
SQL Server中翻转bit字段有两种常用的稳定写法,二选一即可:
- 写法1:用按位取反符
~直接取反UPDATE SelectedType SET [列名] = ~[列名] WHERE P_ID = @id - 写法2:用算术运算实现翻转,可读性更高
UPDATE SelectedType SET [列名] = 1 - [列名] WHERE P_ID = @id
注意:动态拼接列名时最好加上方括号[],避免列名和SQL关键字冲突引发报错
2. 原有代码的问题修正
你现有代码存在几个明显错误,需要同步调整:
- 事务提交、连接关闭操作不能放在for循环内部,否则第一次循环执行完就会提交事务、关闭连接,后续循环直接报错,需要挪到整个for循环执行结束后
- 直接拼接列名存在SQL注入风险,需要先对传入的列名字符串做合法性校验,比如限制只能包含字母、数字、下划线,且前缀为
type_ - 你给出的表示例中主键是
P_ID不是id,WHERE条件要对应修改 - 原SQL中额外加的
AND 列名 = @列名条件完全冗余,也不需要给对应列传参
3. 修正后的完整代码
public bool UpdatePredictSubGoalType(int id, string _selectedTypes) { string a = "[]"; string item = _selectedTypes; if (!item.Contains('[') && !item.Contains(']')) { string c = a.Insert(1, _selectedTypes); item = c; } bool res = false; JArray Ja = JArray.Parse(item); // 合法列名正则校验规则,避免SQL注入 var validColRegex = new System.Text.RegularExpressions.Regex(@"^type_[0-9_]+$"); SqlTransaction trans = null; SqlConnection conn = null; try { using (conn = new SqlConnection(CommonDA.GetConnectionString())) { conn.Open(); trans = conn.BeginTransaction(); try { for (int i = 0; i < Ja.Count; i++) { string x = Ja[i]["value"]?.ToString()?.Trim(); // 校验列名合法性,非法值直接跳过 if (string.IsNullOrEmpty(x) || !validColRegex.IsMatch(x)) continue; SqlCommand cmd = conn.CreateCommand(); // 核心翻转逻辑,这里用1-字段的写法,也可以换成~[x] string sqlstr = $@"UPDATE SelectedType SET [{x}] = 1 - [{x}] WHERE P_ID = @id"; cmd.CommandText = sqlstr; cmd.Transaction = trans; cmd.Parameters.AddWithValue("@id", id); cmd.ExecuteNonQuery(); } // 所有列更新完成后再提交事务 trans.Commit(); res = true; } catch (Exception Err) { trans.Rollback(); CommonLB.SystemError(Err.Message); CommonLB.SystemError("Data", "SQL执行出错"); } finally { conn?.Close(); } } } catch (Exception Err) { throw new ApplicationException(Err.Message, Err); } return res; }
内容的提问来源于stack exchange,提问作者Thomas5566
相关产品推荐
相关产品推荐

