如何用参数替换的SQL捕获?(.NET,SqlCommand)

Bry*_*yan 4 .net sql vb.net ado.net sqlcommand

如果在参数替换后有一种简单的方法可以获得完整的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)
Run Code Online (Sandbox Code Playgroud)

我曾假设Prepare()会做替换,但显然不是.

思考?建议吗?提前致谢.

Pat*_*her 6

不,.Prepare不这样做,事实上命令中没有.参数值永远不会替换为实际的命令字符串.它被单独发送到DB,这有几个原因:

  • 这允许sqlserver(或其他dbs)缓存查询的查询计划,并在下次重用它.每次向数据库发送不同的commandtext字符串时,数据库每次都必须开发一个计划.
  • 通过将参数发送到数据库分区,有一个针对SQL注入攻击的自然防御.

除非你使用一个非常老的数据库(sql server 7?),.Prepare()否则没有必要,并且实际上并没有为你做任何事情.它曾经有用,因为它会在服务器上编译查询,但现在自动完成.我.Prepare()好久没用了.

Hmmmmm.看这里似乎.Prepare()仍然为你做了一些事情:如果任何值大于参数定义的长度,.Prepare()会截断该值,这样当你执行时你不会得到错误并且查询成功.凉.


Cor*_*ter 5

我通常在我的项目中添加一个实用程序函数,给定一个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
Run Code Online (Sandbox Code Playgroud)

当我写这篇文章的时候,我发现它不是单独记录参数值,而是可以做一些String.Replace()来将参数值替换成查询然后记录它:

For Each p As DbParameter In cmd.Parameters
    msg = msg.Replace(p.ParameterName, p.Value.ToString())
Next
Run Code Online (Sandbox Code Playgroud)