2026-07-19 10:33:21
Dapper 可以通过参数化查询防止 SQL 注入,并通过实现“伪位置参数”(Pseudo-Positional Parameters)功能支持多种数据库的参数格式差异。
防 SQL 注入的原理Dapper 默认使用参数化查询,将 SQL 语句中的参数值与 SQL 语句本身分离,避免直接拼接字符串导致的注入风险。例如:
using (IDbConnection conn = CreateConnection()) { string sqlCommandText = @"SELECT * FROM USERS WHERE ID=@ID"; Users user = conn.Query<Users>(sqlCommandText, new { ID = 2 }).FirstOrDefault(); Console.WriteLine(user.Name); }此代码中,@ID 是参数占位符,实际值通过匿名对象 new { ID = 2 } 传递,Dapper 会将其转换为数据库兼容的参数格式,从而防止 SQL 注入。
不同数据库的参数格式差异不同数据库对参数占位符的语法要求不同:
若直接使用 @ID 编写 SQL,在 Oracle 数据库中会报错,因为其仅支持 :ID 格式。

Dapper 内部通过 Pseudo-Positional Parameters 机制,为不支持命名参数的数据库(如 OleDB)提供兼容性支持。其核心逻辑如下:
为支持更多数据库(如 Oracle 和 OleDB),可自定义参数替换逻辑,通过正则表达式动态调整占位符格式:
private static readonly Regex pseudoRegex = new Regex(@"$([p{L}_][p{L}p{N}_]*)$", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant | RegexOptions.Compiled); public static string ReplacePseudoParameter(IDbConnection conn, string cmdText) { return pseudoRegex.Replace(cmdText, match => { var key = match.Groups[1].Value; if (conn is OleDbConnection) { return "?"; // OleDB 仅支持 ? } return (conn is OracleConnection ? ":" : "@") + key; // Oracle 用 :,其他用 @ }); }使用方式:在参数名两侧添加 $ 符号,调用 ReplacePseudoParameter 方法动态替换占位符:
string sqlCommandText = @"SELECT * FROM USERS WHERE ID=$ID$"; Users user = conn.Query<Users>(ReplacePseudoParameter(conn, sqlCommandText), new { ID = 2 }).FirstOrDefault();默认支持命名参数的数据库(如 SQL Server、MySQL)直接使用 @param 格式。
通过自定义“伪位置参数”逻辑,可兼容 Oracle(:param)和 OleDB(?)等特殊格式。
此方案在保持 Dapper 轻量级特性的同时,解决了跨数据库参数格式差异问题,适用于需要支持多种数据库的通用数据访问层开发。