如何 log/get Dapper Extensions 自动生成的 SQL 查询?

How to log/get a SQL query auto-generated by Dapper Extensions?

我正在使用 Dapper Extensions (DE) 作为 ORM。它在使用存储库模式实现的数据访问层中使用。 SQL Express 是后端 RDBMS。

DE 自动为我生成大部分查询。我想记录那些自动生成的查询以用于调试目的。

我可以通过两种方式实现此目的:-

  1. 获取DE生成的SQL查询(执行前或执行后)并将其写入日志。 这是我的首选方式,因为我已经有了我的日志记录模块(使用 log4net)。我唯一需要的是 DE 生成的 SQL。
  2. 将 DE 与一些日志记录工具集成。我阅读了 this 个答案。看起来可以使用 MiniProfiler 工具;但正如我上面所说,我已经有了我的日志记录模块。我不想使用其他工具来记录 SQL 查询。

如何在不使用任何其他日志工具的情况下 log/get SQL 由 Dapper Extensions 自动生成的查询?

other 类似的问题是关于 Dapper 的。这个问题是关于 Dapper Extensions 的。

Dapper Extensions 项目开源;每个人都知道这一点。我从 GitHub 下载并修改它以满足我的需要。

Dapper Extensions build/generate SQL 在 SqlGeneratorImpl class 内部查询。 class 中有多种方法可以生成各种查询。

我在 DapperExtensions.DapperExtensions static class 中添加了以下 属性:

static string lastGeneratedQuery;
public static string LastGeneratedQuery
{
    get
    {
        lock(_lock)
        {
            return lastGeneratedQuery;
        }
    }
    internal set
    {
        lock(_lock)
        {
            lastGeneratedQuery = value;
        }
    }
}

另外,在SqlGeneratorImplclass的各种方法中设置这个属性。以下是我如何在 Select 方法中设置它的示例。

public virtual string Select(IClassMapper classMap, IPredicate predicate, IList<ISort> sort, IDictionary<string, object> parameters)
{
    ......
    ......

    StringBuilder sql = new StringBuilder(string.Format("SELECT {0} FROM {1}",
    ......
    ......

    DapperExtensions.LastGeneratedQuery = sql.ToString();

    return sql.ToString();
}

基本测试运行很好;我还没有彻底测试过这个。如果有任何更改,我会更新此答案。

请注意,我不推荐将此作为标准解决方案;这只是一个适合我需要的技巧。我真的很想将其视为图书馆的一项常规功能。 如果您有更好的解决方案,请post回答。否则,请发表评论以改进此处建议的解决方案

master 分支中合并 this pull request 后,希望现在可以开箱即用,无需再下载和修改工具包源代码。请注意,我尚未对此进行验证。

查看关于使用 Dapper 执行相同操作的 from @MarcGravell and this 问题,MiniProfiler.Integrations 是为 Dapper 扩展实现日志记录的更好方法。

上面的链接问题是关于 Dapper 的。但 Dapper Extensions 在内部使用 Dapper。因此,如果为 Dapper 实现了日志记录,同样适用于 Dapper Extensions。

可以在 GitHub 上找到更多详细信息。

示例代码如下:

var factory = new SqlServerDbConnectionFactory(connectionString);
CustomDbProfiler cp = new CustomDbProfiler();
using(var connection = DbConnectionFactoryHelper.New(factory, cp))
{
    //DB Code
}
string log = cp.ProfilerContext.GetCommands();

如果适合您的需要,您可以使用内置 CustomDbProfilerCustomDbProfiler.Currentcp.ProfilerContext.GetCommands() 将 return 所有命令(成功和失败),无论您调用该方法多少次。我不确定,但它可能在内部维护连接字符串(StringBuilder 可能)。如果是这种情况,这可能会降低性能。但是,就我而言,默认情况下禁用日志记录。我只在需要调试某些东西时才启用日志记录。所以这对我来说不是问题。

如果在非常大的范围内使用单个连接,这也可能会引发内存占用问题。为避免这种情况,请确保 CustomDbProfiler 实例已正确处理。

如问题所述,最初,我想避免这种方式(使用外部 tool/library)。但是,MiniProfiler.Integrations 并没有写日志本身。我可以简单地获取所有生成的查询并将它们提供给我的记录器模块以转储到文件中。所以,这个现在看起来更适合我。


MiniProfiler.dll 在内部实现了类似的逻辑(在 StackExchange.Profiling.Data.ProfiledDbConnectionStackExchange.Profiling.Data.ProfiledDbCommand 类 中),在 and here 中提到。所以,如果我决定(将来可能)绕过 MiniProfiler,我可以自己使用这个实现。