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

C#中如何正确参数化SQL查询以避免SQL注入?

现有代码问题分析
  • 你当前的参数化写法确实无法正常运行,核心问题有3个:
    1. 参数名重复冲突:每次循环你都往SQL里追加同一个:MG_GROUP_ID占位符,最终SQL里会有N个同名占位符,数据库无法区分每个占位符对应的实际值,会导致参数匹配完全错误。
    2. OleDb适配问题:OleDb驱动本身不支持命名参数,只会按占位符出现的先后顺序匹配参数,你写的:参数名格式本质和?占位符没有区别,就算参数名不重复也会有顺序匹配的隐患。
    3. 逻辑冗余错误:循环内部每次都新建连接、命令对象,且只赋值了CommandText和参数,没有实际执行查询的逻辑,完全不符合原始代码拼接完整SQL后统一执行的逻辑。
正确参数化实现方案

因为你是动态生成查询列,每个DECODE函数里的MG_GROUP_ID都是独立的固定值,我们需要给每个值分配唯一的占位符,统一收集参数后再执行:

// 初始化SQL和全局参数列表
StringBuilder sqlBuilder = new StringBuilder();
List<OleDbParameter> parameters = new List<OleDbParameter>();
int paramIndex = 0;

// 拼接Original列部分
foreach (DataRow row in dsMrgnGroups.Tables[0].Rows)
{
    // 每个占位符用唯一序号区分,OleDb用?做占位符
    sqlBuilder.AppendFormat("LTRIM(TO_CHAR(MAX(DECODE(CMD_MGG_ID, ?, CMD_MRGN_ORG_VALUE)), '999999999999999990.99')) AS Original_{0},", paramIndex);
    // 直接传原值,不要ToString()避免类型转换错误
    parameters.Add(new OleDbParameter($"@MG_GROUP_ID_{paramIndex}", row["MG_GROUP_ID"]));
    paramIndex++;
}

// 拼接MemUploaded列部分
foreach (DataRow row in dsMrgnGroups.Tables[0].Rows)
{
    sqlBuilder.AppendFormat("LTRIM(TO_CHAR(MAX(DECODE(CMD_MGG_ID, ?, CMD_MRGN_UPD_VALUE)), '999999999999999990.99')) AS MemUploaded_{0},", paramIndex);
    parameters.Add(new OleDbParameter($"@MG_GROUP_ID_{paramIndex}", row["MG_GROUP_ID"]));
    paramIndex++;
}

// 去掉末尾多余的逗号
if (sqlBuilder.Length > 0)
{
    sqlBuilder.Length--;
}

// 补全SQL剩余部分(替换成你原始代码里的FROM、WHERE、GROUP BY等逻辑)
sqlBuilder.Insert(0, "SELECT ");
sqlBuilder.Append(" FROM YOUR_TABLE_NAME");

// 统一执行查询
using (OleDbConnection conn = new OleDbConnection(_connString))
using (OleDbCommand cmd = conn.CreateCommand())
{
    try
    {
        conn.Open();
        cmd.CommandText = sqlBuilder.ToString();
        cmd.Parameters.AddRange(parameters.ToArray());
        // 这里补充你的查询执行逻辑,比如ExecuteReader、ExecuteScalar等
    }
    catch (Exception ex)
    {
        _messageObj.WriteLog("Exception: DLL ->UpdateMarginsDLL -> GetMarginDetailsCM: " + ex.Message, _tmid, 1);
    }
}
函数返回参数化查询的实现

你可以自定义一个简单的传输类,或者直接返回元组,把SQL和参数一起返回即可,示例:

// 自定义传输类
public class ParameterizedSql
{
    public string SqlText { get; set; }
    public List<OleDbParameter> Parameters { get; set; }
}

// 函数返回示例
public ParameterizedSql BuildMarginQuery(DataSet dsMrgnGroups)
{
    // 此处放上述拼接SQL、收集参数的逻辑
    return new ParameterizedSql
    {
        SqlText = sqlBuilder.ToString(),
        Parameters = parameters
    };
}

调用方拿到返回值后,直接把SqlText赋值给CommandText,遍历Parameters添加到命令的参数集合即可执行。

注意事项
  • 尽量用StringBuilder拼接SQL,避免高频字符串拼接的性能损耗
  • 传参数时不要手动转成字符串,保持原始数据类型,避免数据库隐式转换导致索引失效或者查询错误
  • 所有实现IDisposable的对象(连接、命令、DataReader等)都要用using包裹,自动释放资源

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 06:36:06