【问题标题】:Is there any way to trace\log the sql using Dapper?有没有办法使用 Dapper 跟踪\记录 sql?
【发布时间】:2013-08-30 09:50:18
【问题描述】:

有没有办法将生成的 sql 转储到调试日志之类的?我在 winforms 解决方案中使用它,所以迷你分析器的想法对我不起作用。

【问题讨论】:

    标签: dapper


    【解决方案1】:

    我遇到了同样的问题,并在进行了一些搜索后实现了一些代码,但没有现成的东西。 nuget上有一个包MiniProfiler.Integrations我想分享一下。

    更新V2:支持与其他数据库服务器协同工作,对于MySQL需要MiniProfiler.Integrations.MySql

    以下是使用 SQL Server 的步骤:

    1.实例化连接

    var factory = new SqlServerDbConnectionFactory(_connectionString);
    using (var connection = ProfiledDbConnectionFactory.New(factory, CustomDbProfiler.Current))
    {
     // your code
    }
    

    2.完成所有工作后,根据需要将所有命令写入文件

    File.WriteAllText("SqlScripts.txt", CustomDbProfiler.Current.ProfilerContext.BuildCommands());
    

    【讨论】:

    • 是的,github上有一个仓库github.com/vndevpro/MiniProfiler.Integrations
    • 太棒了。您可能希望将项目站点更改为 nuget 中的那个 github - 目前它似乎指向自身(或以前的版本)
    • 示例中是 System.Data.Entity.Infrastructure.SqlConnectionFactory 吗?似乎找不到“新建”扩展方法或 SqlConnectionFactory 的其他实现。此示例是否特定于 MiniProfiler.Integrations 的特定版本?
    • MySql 的工作就像一个梦想。在 10 分钟内解决了我的问题。更改为 CustomDbProfiler.Current.ProfilerContext.GetCommands()。谢谢!
    • 这个答案对 Net Core 有效吗? CustomDbProfiler.Current.ProfilerContext 我不见了。
    【解决方案2】:

    Dapper 目前在此处没有检测点。正如您所注意到的,这可能是由于我们(作为作者)使用迷你分析器来处理这个事实。但是,如果它有帮助,mini-profiler 的核心部分实际上被设计为与架构无关,而且我知道其他人将它与 winforms、wpf、wcf 等一起使用——这将使您可以访问分析/跟踪连接包装器.

    理论上,添加一些全面的捕获点是完全可能的,但我担心两件事:

    • (主要)安全性:由于 dapper 没有上下文的概念,真的很容易让恶意代码悄悄附加以嗅探通过 dapper 传输的所有 sql 流量;我真的不喜欢这样的声音(这不是“装饰器”方法的问题,因为调用者拥有连接,因此拥有日志上下文)
    • (次要)性能:但是......事实上,很难说简单的委托检查(在大多数情况下可能是 null)会产生很大的影响

    当然,您可以做的另一件事是:从 mini-profiler 中窃取连接包装代码,并将 profiler-context 的内容替换为:Debug.WriteLine 等。

    【讨论】:

    • 嗨,马克,你能举一个你担心的攻击的例子吗?
    【解决方案3】:

    这并不详尽,本质上是一个小技巧,但如果你有你的 sql 并且你想初始化你的参数,它对于基本调试很有用。

    public static class DapperExtensions
        {
            if (args is null) throw new ArgumentNullException(nameof(args));
            public static string ArgsAsSql(this DynamicParameters args)
            {
                var sb = new StringBuilder();
                foreach (var name in args.ParameterNames)
                {
                    var pValue = args.Get<dynamic>(name);
    
                    var type = pValue.GetType();
    
                    if (type == typeof(DateTime))
                        sb.AppendFormat("DECLARE @{0} DATETIME ='{1}'\n", name, pValue.ToString("yyyy-MM-dd HH:mm:ss.fff"));
                    else if (type == typeof(bool))
                        sb.AppendFormat("DECLARE @{0} BIT = {1}\n", name, (bool)pValue ? 1 : 0);
                    else if (type == typeof(int))
                        sb.AppendFormat("DECLARE @{0} INT = {1}\n", name, pValue);
                    else if (type == typeof(List<int>))
                        sb.AppendFormat("-- REPLACE @{0} IN SQL: ({1})\n", name, string.Join(",", (List<int>)pValue));
                    else
                        sb.AppendFormat("DECLARE @{0} NVARCHAR(MAX) = '{1}'\n", name, pValue.ToString());
                }
    
                return sb.ToString();
            }
        }
    

    然后,您可以在即时或监视窗口中使用它来获取 SQL。

    【讨论】:

      【解决方案4】:

      您应该考虑使用位于 SQL Management Studio → Extras → SQL Server Profiler 菜单中的 SQL 分析器(不需要 Dapper 扩展 -当他们也有一个 SQL 分析器工具时,可能会与其他 RDBMS 一起使用)。

      然后,开始一个新的会话。

      例如,你会得到类似的东西(你会看到所有参数和完整的 SQL 字符串):

      exec sp_executesql N'SELECT * FROM Updates WHERE CAST(Product_ID as VARCHAR(50)) = @appId AND (Blocked IS NULL OR Blocked = 0) 
                          AND (Beta IS NULL OR Beta = 0 OR @includeBeta = 1) AND (LangCode IS NULL OR LangCode IN (SELECT * FROM STRING_SPLIT(@langCode, '','')))',N'@appId nvarchar(4000),@includeBeta bit,@langCode nvarchar(4000)',@appId=N'fea5b0a7-1da6-4394-b8c8-05e7cb979161',@includeBeta=0,@langCode=N'de'
      

      【讨论】:

        【解决方案5】:

        试试Dapper.Logging

        您可以从 NuGet 获取它。它的工作方式是将创建实际数据库连接的代码传递给创建包装连接的工厂。每当打开或关闭包装的连接或您对其运行查询时,它都会被记录下来。您可以配置日志消息模板和其他设置,例如是否保存 SQL 参数。还保存了经过的时间。

        在我看来,唯一的缺点是文档很少,但我认为这只是因为它是一个新项目(在撰写本文时)。我不得不深入研究一下 repo 以了解它并根据我的喜好对其进行配置,但现在它运行良好。

        来自文档:

        该工具由 DbConnectionDbCommand 跟踪执行时间并将消息写入 ILogger&lt;T&gt;ILogger&lt;T&gt; 可以由任何日​​志框架处理 (例如 Serilog)。结果类似于默认的 EF Core 日志记录 行为。

        lib 声明了一个帮助方法来注册 IDbConnectionFactory 在 IoC 容器中。连接工厂是 SQL 提供程序不可知。这就是为什么你必须指定真正的工厂 方法:

        services.AddDbConnectionFactory(prv => new SqlConnection(conStr));
        

        注册后,IDbConnectionFactory可以注入 需要 SQL 连接的类。

        private readonly IDbConnectionFactory _connectionFactory;
        public GetProductsHandler(IDbConnectionFactory connectionFactory)
        {
            _connectionFactory = connectionFactory;
        }
        

        IDbConnectionFactory.CreateConnection 将返回一个装饰的 记录活动的版本。

        using (DbConnection db = _connectionFactory.CreateConnection())
        {
            //...
        }
        

        【讨论】:

        • 当你试图理解一个遗留代码库时,该代码库实际上有数千个创建 SQL 连接的位置,并且都略有不同,因此没有可行的方法来解决这个问题。变化......只有对现有代码完全透明的东西(除了在启动时的单个地方挂钩初始化)才是可行的。是的,我确实理解安全问题......
        【解决方案6】:

        只是在这里添加一个更新,因为我看到这个问题仍然有很多点击 - 这些天我使用Glimpse(现在似乎已经死了)或Stackify Prefix,它们都具有 sql 命令跟踪功能。

        当我问原始问题时,这并不是我想要的,而是解决了同样的问题。

        【讨论】:

        • 瞥见没死?
        • @Kiquenet 嗯,看来 - 很长一段时间没有使用它所以我从来没有注意到。很遗憾 - 真的很棒。
        猜你喜欢
        • 2011-11-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-10-16
        • 1970-01-01
        • 2021-05-09
        • 1970-01-01
        相关资源
        最近更新 更多