有没有办法在param替换后从SqlCommand获取完整的sql文本?

时间:2009-08-10 13:37:26

标签: .net sql-server ado.net

我使用包含参数的SQL查询创建了一个SqlCommand。 我将所有参数添加到类中。

是否有一种简单的方法可以在将结果发送到数据库之前查看生成的SQL查询?

这对于调试目的很方便。 (例如,复制整个查询并在管理工作室中运行以尝试查明问题)

[R

3 个答案:

答案 0 :(得分:4)

不,因为实际上没有替换。查询按原样传递给服务器,参数分别传递。

但是,您可以编写一个方法来将参数占位符替换为实际参数值...这就是我在其中一个应用程序中所做的,我会尽快发布代码。


以下是我使用的代码,但它适用于Oracle Lite数据库,因此需要进行一些调整才能将其与另一个RDBMS一起使用。

    public void Log(IDbCommand cmd)
    {
        StringBuilder sb = new StringBuilder(cmd.CommandText);
        for (int i = 0; i < cmd.Parameters.Count; i++)
        {
            int pos = sb.ToString().IndexOf("?");
            if (pos > 0)
                sb.Replace("?", FormatParameter(cmd.Parameters[i]), pos, 1);
        }
        Log(sb.ToString());
    }

    private string FormatParameter(object prm)
    {
        IDbDataParameter p = prm as IDbDataParameter;
        if (p.Value == null || p.Value == DBNull.Value)
            return "NULL";
        switch (p.DbType)
        {
            case DbType.AnsiString:
            case DbType.AnsiStringFixedLength:
            case DbType.String:
            case DbType.StringFixedLength:
                string s = p.Value as string;
                return string.Format("'{0}'", s.Replace("'", "''"));

            case DbType.Binary:
                byte[] b = p.Value as byte[];
                return HexString(b);

            case DbType.Date:
            case DbType.DateTime:
            case DbType.DateTime2:
                DateTime d = (DateTime)p.Value;
                return string.Format("to_date('{0}', 'dd/mm/yyyy hh24:mi')", d.ToString("dd/MM/yyyy HH:mm"));

            default:
                return p.Value.ToString();
        }
    }

    private string HexString(byte[] bytes)
    {
        StringBuilder sb = new StringBuilder();
        for (int i=0; i < bytes.Length; i++)
            sb.AppendFormat("{0:X2}", bytes[i]);
        return sb.ToString();
    }

答案 1 :(得分:2)

好吧,你可以在SQL事件探查器中看到整个查询(不可否认的是之后它被发送到数据库)但是它为你提供了一种简单的方法来复制粘贴语句,这样你就可以调试在Management Studio内部。

只需添加新的跟踪,运行执行数据库调用的代码,然后从生成的捕获事件中复制粘贴命令。

答案 2 :(得分:0)

在发布此问题之前,我只是重新阅读了您的问题。虽然这种技术可能无法直接应用于.net,但您可能能够找到类似的东西。所以:

我最近不得不在T-SQL中进行大量的动态编码,并且我已经提出了以下例程。假设你有一大堆代码:

DECLARE
  @Command    nvarchar(max)
 ,@SearchFor  int

SET @Command = 'SELECT * from MyTable where PrimaryKey = @SearchFor'
SET @SearchFor = 1

EXECUTE sp_executesql
  @Command
 ,N'@SearchFor int'
 ,@SearchFor

这当然非常简单 - 如果你需要做动态代码,你将会遇到复杂到极其复杂的查询,并且正如你所发现的那样,调试起来非常困难。以下是我重写上述代码的方法:

DECLARE
  @Command    nvarchar(max)
 ,@SearchFor  int
 ,@Debug      int
    --  0 = Run it
    --  1 = Run and display it
    --  2 = Display it 

SET @Command = 'SELECT * from MyTable where PrimaryKey = @SearchFor'
SET @SearchFor = 1
SET @Debug = 1

IF @Debug > 0
    --  Show the command that would be run
    PRINT replace(@Command, '@SearchFor', cast(@SearchFor as varchar(10)))

IF @Debug < 2
    --  Run it
    EXECUTE sp_executesql
      @Command
     ,N'@SearchFor int'
     ,@SearchFor

这是编写和调试的额外代码,但是一旦它就位并正常工作,它在调试情况下就非常宝贵。如果它是存储过程的一部分,请使@Debug参数默认为0,并确保如果设置为2,则该过程实际上不执行任何操作。