有没有办法将生成的 sql 转储到调试日志之类的?我在 winforms 解决方案中使用它,所以迷你分析器的想法对我不起作用。
6 回答
在进行了一些搜索但没有现成的东西后,我遇到了同样的问题并实现了一些代码。我想分享一个关于 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());
Dapper 目前在这里没有检测点。正如您所指出的,这可能是由于我们(作为作者)使用迷你分析器来处理这个事实。但是,如果它有帮助,mini-profiler 的核心部分实际上被设计为与架构无关,而且我知道其他人将它与 winforms、wpf、wcf 等一起使用——这将使您可以访问分析/跟踪连接包装器.
理论上,添加一些全面的捕获点是完全可能的,但我担心两件事:
- (主要)安全性:由于 dapper 没有上下文的概念,恶意代码很容易悄悄附加以嗅探通过 dapper 的所有 sql 流量;我真的不喜欢那样的声音(这不是“装饰器”方法的问题,因为调用者拥有连接,因此是日志上下文)
- (次要)性能:但是......事实上,很难说简单的委托检查(可能
null
在大多数情况下)会产生很大的影响
当然,您可以做的另一件事是:从 mini-profiler 窃取连接包装器代码,并将 profiler-context 的内容替换为:Debug.WriteLine
等。
这不是详尽无遗的,本质上是一个 hack,但如果你有你的 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。
您应该考虑使用位于SQL Management Studio → Extras → SQL Server Profiler菜单中的 SQL 分析器(不需要 Dapper 扩展 - 当其他 RDBMS 也有 SQL 分析器工具时也可以使用)。
然后,开始一个新的会话。
例如,您将获得类似这样的信息(您会看到所有参数和完整的 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'
试试Dapper.Logging。
您可以从 NuGet 获取它。它的工作方式是将创建实际数据库连接的代码传递给创建包装连接的工厂。每当打开或关闭包装的连接或您对其运行查询时,它都会被记录下来。您可以配置日志消息模板和其他设置,例如是否保存 SQL 参数。还保存了经过的时间。
在我看来,唯一的缺点是文档很少,但我认为这只是因为它是一个新项目(在撰写本文时)。我不得不深入研究一下 repo 以了解它并根据我的喜好对其进行配置,但现在它运行良好。
从文档中:
该工具由简单的装饰器组成,用于
DbConnection
跟踪DbCommand
执行时间并将消息写入ILogger<T>
. 可以由任何日ILogger<T>
志框架(例如 Serilog)处理。结果类似于默认的 EF Core 日志记录行为。
IDbConnectionFactory
lib 声明了一个用于在 IoC 容器中注册的辅助方法 。连接工厂与 SQL Provider 无关。这就是为什么你必须指定真正的工厂方法: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()) { //... }
只是在这里添加一个更新,因为我看到这个问题仍然有很多点击 - 这些天我使用Glimpse(现在似乎它已经死了)或Stackify Prefix,它们都具有 sql 命令跟踪功能。
当我问原始问题但解决相同的问题时,这并不是我想要的。