From .NET can I get the full SQL string generated by a SqlCommand object (with SQL Parameters)?

心不动则不痛 提交于 2019-11-28 13:40:26
Jesus Ramos

A simple loop replacing all the parameter names with their values will provide you with something similar to what the end result is, but there are several problems.

  1. Since the SQL is never actually rebuilt using the parameter values, things like newlines and quotes don't need to be considered
  2. Parameter names in comments are never actually processed for their value, but left as-is

With those in place, and taking into account parameter names that starts with the same characters, like @NAME and @NAME_FULL, we can replace all the parameter names with the value that would be in the place of that parameter:

string query = cmd.CommandText;
foreach (SqlParameter p in cmd.Parameters.OrderByDescending(p => p.ParameterName.Length))
{
    query = query.Replace(p.ParameterName, p.Value.ToString());
}

there is one problem left with this, however, and that is if a parameter is a string, then the SQL that initially looks like this:

SELECT * FROM yourtable WHERE table_code = @CODE

will look like this:

SELECT * FROM yourtable WHERE table_code = SOME CODE WITH SPACES

This is clearly not legal SQL, so we need to account for some parameter-types as well:

DbType[] quotedParameterTypes = new DbType[] {
    DbType.AnsiString, DbType.Date,
    DbType.DateTime, DbType.Guid, DbType.String,
    DbType.AnsiStringFixedLength, DbType.StringFixedLength
};
string query = cmd.CommandText;

var arrParams = new SqlParameter[cmd.Parameters.Count];
cmd.Parameters.CopyTo(arrParams, 0);

foreach (SqlParameter p in arrParams.OrderByDescending(p => p.ParameterName.Length))
{
    string value = p.Value.ToString();
    if (quotedParameterTypes.Contains(p.DbType))
        value = "'" + value + "'";
    query = query.Replace(p.ParameterName, value);
}
DOK

There have been a couple of similar questions here.

The most compelling answer was provided to this question: How to get the generated SQL-Statment from a SqlCommand-Object?

and the answer was:

You can't, because it does not generate any SQL.

The parameterized query (the one in CommandText) is sent to the SQL Server as the equivalent of a prepared statement. When you execute the command, the parameters and the query text are treated separately. At no point in time a complete SQL string is generated.

You can use SQL Profiler to take a look behind the scenes.

The CommandText property (or calling ToString()) on your command will give you all of the SQL, with a small exception. It will definitely give you anything you see in the debugger. Note that this won't give you parameter values, but it will give you the actual command.

The only caveat is that when CommandType is Text, the ADO.NET framework will often (in fact, almost always) use sp_executesql to execute the command rather than executing the command directly against the connection. In that sense, it's not possible to obtain the exact SQL that gets executed.

I haven't tried this, but you may be able to use Capture Mode if you are willing to use SMO:

http://msdn.microsoft.com/en-us/library/ms162182(v=sql.120).aspx

I like Jesus Ramos answer, but I needed support for output parameters. (I also used a string builder to generate the content.)

Declare Parameter for output parameters

 foreach (SqlParameter p in arrParams.Where(x => x.Direction == ParameterDirection.Output || x.Direction == ParameterDirection.InputOutput))
    {
        // todo : I only needed a couple of types supported, you could add addition types
        string dbtype = string.Empty;
        switch (p.DbType)
        {
            case DbType.Guid:
                dbtype = "uniqueidentifier";
                break;
            case DbType.Int16:
            case DbType.Int64:
            case DbType.Int32:
                dbtype = "int";
                break;
            case DbType.String:
                dbtype = "varchar(max)";
                break;
        }

        query.Append(string.Format(" Declare {0}_ {1}\n", p.ParameterName, dbtype));
    }

Build Main Parameter Area

foreach (SqlParameter p in arrParams)
    {
        bool isLast = p == last;
        string value = p.Value.ToString();
        if (quotedParameterTypes.Contains(p.DbType))
            value = "'" + value + "'";
        if (p.Direction == ParameterDirection.InputOutput || p.Direction == ParameterDirection.Output)
        {
            query.Append(string.Format("{0} = {0}_ out{2}\n", p.ParameterName, value, isLast ? "" : ","));
        }
        else
        {
            query.Append(string.Format("{0} = {1}{2}\n", p.ParameterName, value, isLast ? "" : ","));
        }
    }

List Output Parameter results

foreach (SqlParameter p in arrParams.Where(x => x.Direction == ParameterDirection.Output || x.Direction == ParameterDirection.InputOutput))
    {
        query.Append(string.Format(" select {0}_ {1}\n", p.ParameterName, p.ParameterName.Substring(1)));
    }

Full Code:

        public static string GetProcedureDebugInformation(SqlCommand cmd, [System.Runtime.CompilerServices.CallerMemberName] string caller = null, [System.Runtime.CompilerServices.CallerFilePath] string filePath = null, [System.Runtime.CompilerServices.CallerLineNumber] int? lineNumber = null)
    {
        // Collection of parameters that should use quotes
        DbType[] quotedParameterTypes = new DbType[] {
            DbType.AnsiString, DbType.Date,
            DbType.DateTime, DbType.Guid, DbType.String,
            DbType.AnsiStringFixedLength, DbType.StringFixedLength
        };

        // String builder to contain generated string
        StringBuilder query = new StringBuilder();

        // Build some debugging information using free compiler information
        query.Append(filePath != null ? filePath : ""
        + (lineNumber.HasValue ? lineNumber.Value.ToString() : "")
        + (lineNumber.HasValue || !string.IsNullOrWhiteSpace(filePath) ? "\n\n" : ""));
        query.Append("\n\n");

        var arrParams = new SqlParameter[cmd.Parameters.Count];
        cmd.Parameters.CopyTo(arrParams, 0);

        // Declare Parameter for output parameters
        foreach (SqlParameter p in arrParams.Where(x => x.Direction == ParameterDirection.Output || x.Direction == ParameterDirection.InputOutput))
        {
            // todo : I only needed a couple of types supported, you could add addition types
            string dbtype = string.Empty;
            switch (p.DbType)
            {
                case DbType.Guid:
                    dbtype = "uniqueidentifier";
                    break;
                case DbType.Int16:
                case DbType.Int64:
                case DbType.Int32:
                    dbtype = "int";
                    break;
                case DbType.String:
                    dbtype = "varchar(max)";
                    break;
            }

            query.Append(string.Format(" Declare {0}_ {1}\n", p.ParameterName, dbtype));
        }

        // Set Exec Text
        query.Append(string.Format("\n exec {0}\n", cmd.CommandText));
        var last = arrParams.LastOrDefault();

        //Build Main Parameter Area
        foreach (SqlParameter p in arrParams.OrderByDescending(p => p.ParameterName.Length))
        {
            bool isLast = p == last;
            string value = p.Value.ToString();
            if (quotedParameterTypes.Contains(p.DbType))
                value = "'" + value + "'";
            if (p.Direction == ParameterDirection.InputOutput || p.Direction == ParameterDirection.Output)
            {
                query.Append(string.Format("{0} = {0}_ out{2}\n", p.ParameterName, value, isLast ? "" : ","));
            }
            else
            {
                query.Append(string.Format("{0} = {1}{2}\n", p.ParameterName, value, isLast ? "" : ","));
            }
        }

        // List Output Parameter results
        foreach (SqlParameter p in arrParams.Where(x => x.Direction == ParameterDirection.Output || x.Direction == ParameterDirection.InputOutput))
        {
            query.Append(string.Format(" select {0}_ {1}\n", p.ParameterName, p.ParameterName.Substring(1)));
        }

        return query.ToString();
    }
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!