6

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

DE 会自动为我生成大部分查询。我想记录这些自动生成的查询以进行调试。

我可以看到有两种方法可以实现这一目标:-

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

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

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

4

2 回答 2

4

查看@MarcGravell 的评论这个关于对 Dapper 做同样的事情的问题,MiniProfiler.Integrations是为 Dapper Extensions 实现日志记录的更好方法。

上面链接的问题是关于 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();

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

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

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


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

于 2018-06-15T12:23:48.723 回答
4

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

Dapper Extensions 在SqlGeneratorImpl类内部构建/生成 SQL 查询。此类中有多种方法可生成各种查询。

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

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

此外,在类的各种方法中设置此属性SqlGeneratorImplSelect以下是我如何在方法中设置它的示例。

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();
}

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

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

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

于 2018-03-16T12:47:41.640 回答