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

.NET 8中Entity Framework获取ExecuteSqlRaw执行的精确SQL

获取ExecuteSqlRaw执行的精确SQL并添加元数据到审计库

针对你用.NET 8 EF Core调用ExecuteSqlRaw后需要获取精确执行SQL并存入审计库的需求,这里提供两个可行方案:

方案1:使用EF Core命令拦截器(推荐)

通过自定义DbCommandInterceptor可以全局捕获所有SQL命令(包括ExecuteSqlRaw执行的),能拿到最终执行的命令文本和参数值,还能在执行前后注入审计逻辑,同时保留EF的参数化安全特性。

实现步骤

  1. 自定义拦截器类,重写对应执行方法(ExecuteSqlRaw属于非查询操作,重写NonQueryExecuting):
public class AuditCommandInterceptor : DbCommandInterceptor
{
    private readonly IAuditRepository _auditRepo;

    public AuditCommandInterceptor(IAuditRepository auditRepo)
    {
        _auditRepo = auditRepo;
    }

    public override InterceptionResult<int> NonQueryExecuting(
        DbCommand command,
        CommandEventData eventData,
        InterceptionResult<int> result)
    {
        // 生成带实际参数值的完整SQL(仅用于审计记录,不要用于执行)
        var fullExecutedSql = ReplaceParamsWithValues(command);
        
        // 构造审计日志,添加自定义元数据
        var auditLog = new AuditLog
        {
            ExecutedSql = fullExecutedSql,
            TemplateSql = command.CommandText,
            Parameters = JsonSerializer.Serialize(
                command.Parameters.Cast<DbParameter>()
                    .ToDictionary(p => p.ParameterName, p => p.Value)
            ),
            OperationTime = DateTime.UtcNow,
            // 补充你的自定义元数据:比如当前用户ID、操作类型等
        };

        // 写入审计数据库
        _auditRepo.Add(auditLog);
        _auditRepo.SaveChanges();

        return base.NonQueryExecuting(command, eventData, result);
    }

    // 辅助方法:将参数占位符替换为实际值
    private string ReplaceParamsWithValues(DbCommand command)
    {
        var sql = command.CommandText;
        foreach (DbParameter param in command.Parameters)
        {
            var valueStr = param.Value switch
            {
                string str => $"'{str.Replace("'", "''")}'",
                DateTime dt => $"'{dt:yyyy-MM-dd HH:mm:ss}'",
                DBNull or null => "NULL",
                _ => param.Value.ToString()
            };
            sql = sql.Replace(param.ParameterName, valueStr);
        }
        return sql;
    }
}
  1. 在依赖注入中注册拦截器:
builder.Services.AddDbContext<YourDbContext>(options =>
{
    options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection"))
           .AddInterceptors(new AuditCommandInterceptor(
               builder.Services.BuildServiceProvider().GetRequiredService<IAuditRepository>()
           ));
});

方案优势

  • 全局生效,无需修改现有ExecuteSqlRaw的调用代码
  • 能准确捕获所有执行的SQL命令及参数细节,解决日志与实际执行SQL不一致的问题
  • 保留EF参数化查询的安全性,审计记录仅用于展示

方案2:在特定代码段内直接处理

如果只需要在局部代码块中记录审计信息,可以手动构造DbCommand,先生成审计用SQL,再执行命令:

// 构造数据库命令
using var command = _dbContext.Database.GetDbConnection().CreateCommand();
command.CommandText = sql;

// 添加传入的参数
foreach (var param in parameters) // 这里的parameters就是你传给ExecuteSqlRaw的params数组
{
    if (param is SqlParameter sqlParam)
    {
        var dbParam = command.CreateParameter();
        dbParam.ParameterName = sqlParam.ParameterName;
        dbParam.Value = sqlParam.Value;
        dbParam.DbType = sqlParam.DbType;
        command.Parameters.Add(dbParam);
    }
}

// 生成审计用的带值SQL
var auditSql = ReplaceParamsWithValues(command);

// 构造审计日志并写入
var auditLog = new AuditLog
{
    ExecutedSql = auditSql,
    TemplateSql = sql,
    // 添加你的自定义元数据
};
_auditRepo.Add(auditLog);
_auditRepo.SaveChanges();

// 执行SQL命令
if (command.Connection.State != ConnectionState.Open)
    command.Connection.Open();
var result = command.ExecuteNonQuery();

注意事项

  • 手动处理参数时要保证参数类型匹配,避免错误
  • 同样不要用生成的带值SQL执行,仅用于审计记录

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 01:07:39