在使用 Dapper 时,默认不输出执行的 SQL 语句,但可以通过几种轻量、实用的方式实现 SQL 日志记录,无需引入重型 ORM 日志框架(如 Serilog + EF 集成)。核心思路是利用 Dapper 的
IDbConnection扩展能力或包装连接对象,捕获命令执行前的 SQL 和参数。
方法一:使用 IDbCommandInterceptor(推荐,Dapper v2.1+)
Dapper 2.1 起原生支持拦截器(
IDbCommandInterceptor),可统一监听所有命令执行过程。这是最干净、侵入性最小的方式。 创建一个实现
IDbCommandInterceptor的类,重写
BeforeExecute方法,在其中记录 SQL、参数、连接信息 通过
Dapper.DefaultCommandInterceptor = new YourSqlLogger();全局注册
BeforeExecute中可访问
command.CommandText、
command.Parameters(注意:参数值需遍历获取,部分参数类型需特殊处理,如
DbNull或数组)
示例片段:
public class SqlLogger : IDbCommandInterceptor{
public void BeforeExecute(IDbCommand command)
{
var sql = command.CommandText;
var paramStr = string.Join(", ", command.Parameters.Cast
Console.WriteLine($"[SQL] {sql} | Params: {paramStr}");
}
// 其他方法可空实现
}
启动时注册:
Dapper.DefaultCommandInterceptor = new SqlLogger();
方法二:包装 IDbConnection(兼容老版本 Dapper)
适用于 Dapper IDbConnection,在
CreateCommand()返回前注入日志逻辑。 封装原始连接(如
SqlConnection),所有方法委托调用 重写
CreateCommand(),返回自定义
IDbCommand包装器 在包装后的
Execute*方法中记录 SQL,再调用原命令执行 适合单元测试 Mock,也便于结合 DI 容器(如注册为 Scoped 服务)
方法三:手动拼接 SQL(仅调试用,不推荐生产)
借助
Dapper.SqlMapper.GenerateSql(内部 API,不稳定)或第三方扩展(如
DapperExtensions),或自己解析匿名对象/ExpandoObject 参数生成占位符 SQL。但该方式无法还原真实执行 SQL(尤其含动态条件、多表 JOIN 时),且不包含实际参数值类型和 DbNull 处理,仅适合快速验证逻辑。 不要用于生产环境日志,易出错、不可靠 可配合
CommandDefinition的
Flags(如
CommandFlags.None)做临时调试开关
基本上就这些。优先用拦截器(方法一),简洁稳定;若项目暂不能升级 Dapper,选连接包装(方法二);手动生成 SQL 仅作临时辅助,别当真。
