如何使用替换的参数捕获 SQL? (.NET,SqlCommand)
Posted
技术标签:
【中文标题】如何使用替换的参数捕获 SQL? (.NET,SqlCommand)【英文标题】:How to capture SQL with parameters substituted in? (.NET, SqlCommand) 【发布时间】:2010-05-19 17:43:19 【问题描述】:是否有一种简单的方法可以在参数替换后返回完整的 SQL 语句?即,我想保留该程序运行的所有 SQL 的日志文件。
或者如果我想这样做,我是否只想摆脱参数,并以老派的方式进行整个查询,在一个大字符串中?
简单示例:我要捕获输出:
SELECT subcatId FROM EnrollmentSubCategory WHERE catid = 1
.. 来自这段代码:
Dim subCatSQL As String = "SELECT subcatId FROM EnrollmentSubCategory WHERE catid = @catId"
Dim connectionString As String = "X"
Dim conn As New SqlConnection(connectionString)
If conn.State = ConnectionState.Closed Then
conn.Open()
End If
Dim cmd As New SqlCommand(subCatSQL, conn)
With cmd
.Parameters.Add(New SqlParameter("@catId", SqlDbType.Int, 1))
End With
Console.WriteLine("Before: " + cmd.CommandText)
cmd.Prepare()
Console.WriteLine("After: " + cmd.CommandText)
我曾假设 Prepare() 会进行替换,但显然不是。
想法?建议?提前致谢。
【问题讨论】:
【参考方案1】:不,.Prepare
没有这样做,实际上命令中没有任何内容。参数值永远不会被替换到实际的命令字符串中。它被单独发送到数据库,这有几个原因:
除非您使用的是非常旧的数据库(sql server 7?),否则.Prepare()
不是必需的,并且实际上不会为您做任何事情。它曾经很有帮助,因为它会在服务器上编译查询,但现在它会自动为您完成。好久没用.Prepare()
了。
嗯嗯。看着here 似乎.Prepare()
仍然为您做一些事情:如果任何值大于参数定义的长度, .Prepare() 会截断该值,以便在执行时不会收到错误并且查询成功。很酷。
【讨论】:
感谢所有答案 - 我选择这个作为答案,因为它最好地解释了推理。谢谢大家!【参考方案2】:我通常在我的项目中添加一个实用函数,给定一个 DbCommand 对象(OracleCommand、SqlCommand 等的父类)将记录查询和参数值。它可能看起来像这样:
Public Shared Sub LogQuery(ByRef cmd As DbCommand)
If cmd.CommandText Is Nothing Or cmd.CommandText.Length = 0 Then
Return
End If
Dim logFile As CLog = New CLog("sql.log")
Dim msg As New StringBuilder
msg.AppendLine("*** Query ***")
msg.AppendLine(cmd.CommandText)
msg.AppendLine("*** End Query ***")
msg.AppendLine("*** Parameters ***")
For Each p As DbParameter In cmd.Parameters
msg.AppendLine(String.Format("0: 1", p.ParameterName, p.Value.ToString()))
Next
msg.AppendLine("*** End Parameters ***")
logFile.WriteLog(msg.ToString() & System.Environment.NewLine)
End Sub
在我写这篇文章的时候,我突然想到,你可以做一点 String.Replace()ing 来将参数值替换到查询中,然后记录它,而不是单独记录参数值:
For Each p As DbParameter In cmd.Parameters
msg = msg.Replace(p.ParameterName, p.Value.ToString())
Next
【讨论】:
我想我也会这样做——它实际上实现了我一直在寻找的东西。【参考方案3】:参数不被替换。 sql原样,参数本身作为参数传递给sp_executesql系统存储过程
【讨论】:
【参考方案4】:发送到 SQL Server 的不是用值替换的变量,而是一个准备好的语句,这样可以重复使用
在 SQL Server 中打开探查器,您将看到正在运行的不是 SELECT subcatId FROM EnrollmentSubCategory WHERE catid = 1
【讨论】:
【参考方案5】:这是recently asked here。正如其他答案所指出的,参数是带外发送的。
如果你想在服务器上进行捕获,Profiler 可能是你想要使用的,你可以create a trace and use it as a startup job。
【讨论】:
【参考方案6】:您可以围绕System.Data.SqlClient
Provider 构建一个包装器(*例如,在配置文件中注册为... * providerName="System.Data.SqlClient"
的提供程序。本质上是一个拦截代理,您可以访问通过 Provider 传递的所有信息,并且可以抽取您需要的内容,聚合和/或丰富它并将其发送到日志。这有点高级,但打开了捕获整个信息范围的大门,并且可以作为单独的关注层插入/替换/删除。
【讨论】:
【参考方案7】:试试 CommandAsSql NuGet 包
【讨论】:
以上是关于如何使用替换的参数捕获 SQL? (.NET,SqlCommand)的主要内容,如果未能解决你的问题,请参考以下文章
java 替换文本中的所有指定的字符串,比如#*替换为sq, #**替换为we, 我使用了replaceAll进行的替换