有没有一种方法可以将生成的SQL转储到Debug日志或其他地方?我正在使用它在WinForms解决方案中,所以Mini-Profiler想法对我不适用。
有没有一种方法可以将生成的SQL转储到Debug日志或其他地方?我正在使用它在WinForms解决方案中,所以Mini-Profiler想法对我不适用。
我遇到了同样的问题,在做一些搜索后实现了一些代码,但没有现成的东西可用。有一个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来处理此问题。但是,如果有帮助的话,mini-profiler的核心部分实际上被设计为架构中立的,我知道其他人也在winforms、wpf、wcf等上使用它——这将使您可以访问性能剖析/跟踪连接包装器。
理论上,完全可以添加一些通用的捕获点,但我担心以下两点:
当然,您还可以做的另一件事是:从mini-profiler中窃取连接包装器代码,并用Debug.WriteLine
等替换性能剖析上下文相关的代码。
您应该考虑使用位于SQL Management Studio菜单中的SQL Profiler → Extras → SQL Server Profiler(不需要Dapper扩展 - 在其他关系型数据库管理系统也可以使用)。
然后,开始一个新会话。
例如,您将看到如下内容(您将看到所有参数和完整的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'
你可以从NuGet获取它。它的工作方式是将创建实际数据库连接的代码传递给一个工厂,该工厂创建包装连接。每当打开或关闭一个包装连接或对其运行查询时,它都将被记录在日志中。您可以配置日志消息模板和其他设置,例如是否保存SQL参数。经过时间也会被保存。
在我看来,唯一的缺点是文档稀少,但我认为这只是因为它是一个新项目(截至本篇写作)。我不得不在存储库中挖掘一段时间才能理解它,并将其配置为我所喜欢的样式,但现在它运行得很好。
文档描述如下:
The tool consists of simple decorators for the
DbConnection
andDbCommand
which track the execution time and write messages to theILogger<T>
. TheILogger<T>
can be handled by any logging framework (e.g. Serilog). The result is similar to the default EF Core logging behavior.The lib declares a helper method for registering the
IDbConnectionFactory
in the IoC container. The connection factory is SQL Provider agnostic. That's why you have to specify the real factory method:
services.AddDbConnectionFactory(prv => new SqlConnection(conStr));
After registration, the
IDbConnectionFactory
can be injected into classes that need a SQL connection.
private readonly IDbConnectionFactory _connectionFactory; public GetProductsHandler(IDbConnectionFactory connectionFactory) { _connectionFactory = connectionFactory; }
The
IDbConnectionFactory.CreateConnection
will return a decorated version that logs the activity.
using (DbConnection db = _connectionFactory.CreateConnection()) { //... }
这并不是详尽无遗的,而且本质上是一种小技巧,但如果您有SQL,并且想要初始化参数,那么它对于基本调试非常有用。设置这个扩展方法,然后在任何地方按需要调用它。
public static class DapperExtensions
{
public static string ArgsAsSql(this DynamicParameters args)
{
if (args is null) throw new ArgumentNullException(nameof(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();
}
}
在这里补充一下,因为我看到这个问题仍然有很多点击量 - 现在我使用 Glimpse(似乎已经不更新了)或Stackify Prefix,它们都具有 SQL 命令跟踪功能。
虽然不完全符合我最初提出的问题,但可以解决相同的问题。
CustomDbProfiler.Current.ProfilerContext
。 - dani herrera