Obter a instrução SQL gerada de um object SqlCommand?

Eu tenho o seguinte código:

Using cmd As SqlCommand = Connection.CreateCommand cmd.CommandText = "UPDATE someTable SET Value = @Value" cmd.CommandText &= " WHERE Id = @Id" cmd.Parameters.AddWithValue("@Id", 1234) cmd.Parameters.AddWithValue("@Value", "myValue") cmd.ExecuteNonQuery End Using 

Gostaria de saber se existe alguma maneira de obter a instrução SQL final como uma String, que deve ser assim:

 UPDATE someTable SET Value = "myValue" WHERE Id = 1234 

Se alguém se pergunta por que eu faria isso:

  • para instruções de log (falha)
  • por ter a possibilidade de copiar e colá-lo para o Enterprise Manager para fins de teste

Embora não seja perfeito, aqui está algo que eu criei para o TSQL – poderia ser facilmente ajustado para outros sabores … Se nada mais lhe daria um ponto de partida para suas próprias melhorias 🙂

Isso faz um trabalho OK em tipos de dados e parâmetros de saída, etc., semelhante ao uso de “executar procedimento armazenado” no SSMS. Usamos principalmente SPs para que o comando “text” não leve em consideração os parâmetros, etc.

  public static String ParameterValueForSQL(this SqlParameter sp) { String retval = ""; switch (sp.SqlDbType) { case SqlDbType.Char: case SqlDbType.NChar: case SqlDbType.NText: case SqlDbType.NVarChar: case SqlDbType.Text: case SqlDbType.Time: case SqlDbType.VarChar: case SqlDbType.Xml: case SqlDbType.Date: case SqlDbType.DateTime: case SqlDbType.DateTime2: case SqlDbType.DateTimeOffset: retval = "'" + sp.Value.ToString().Replace("'", "''") + "'"; break; case SqlDbType.Bit: retval = (sp.Value.ToBooleanOrDefault(false)) ? "1" : "0"; break; default: retval = sp.Value.ToString().Replace("'", "''"); break; } return retval; } public static String CommandAsSql(this SqlCommand sc) { StringBuilder sql = new StringBuilder(); Boolean FirstParam = true; sql.AppendLine("use " + sc.Connection.Database + ";"); switch (sc.CommandType) { case CommandType.StoredProcedure: sql.AppendLine("declare @return_value int;"); foreach (SqlParameter sp in sc.Parameters) { if ((sp.Direction == ParameterDirection.InputOutput) || (sp.Direction == ParameterDirection.Output)) { sql.Append("declare " + sp.ParameterName + "\t" + sp.SqlDbType.ToString() + "\t= "); sql.AppendLine(((sp.Direction == ParameterDirection.Output) ? "null" : sp.ParameterValueForSQL()) + ";"); } } sql.AppendLine("exec [" + sc.CommandText + "]"); foreach (SqlParameter sp in sc.Parameters) { if (sp.Direction != ParameterDirection.ReturnValue) { sql.Append((FirstParam) ? "\t" : "\t, "); if (FirstParam) FirstParam = false; if (sp.Direction == ParameterDirection.Input) sql.AppendLine(sp.ParameterName + " = " + sp.ParameterValueForSQL()); else sql.AppendLine(sp.ParameterName + " = " + sp.ParameterName + " output"); } } sql.AppendLine(";"); sql.AppendLine("select 'Return Value' = convert(varchar, @return_value);"); foreach (SqlParameter sp in sc.Parameters) { if ((sp.Direction == ParameterDirection.InputOutput) || (sp.Direction == ParameterDirection.Output)) { sql.AppendLine("select '" + sp.ParameterName + "' = convert(varchar, " + sp.ParameterName + ");"); } } break; case CommandType.Text: sql.AppendLine(sc.CommandText); break; } return sql.ToString(); } 

isso gera saída ao longo dessas linhas …

 use dbMyDatabase; declare @return_value int; declare @OutTotalRows BigInt = null; exec [spMyStoredProc] @InEmployeeID = 1000686 , @InPageSize = 20 , @InPage = 1 , @OutTotalRows = @OutTotalRows output ; select 'Return Value' = convert(varchar, @return_value); select '@OutTotalRows' = convert(varchar, @OutTotalRows); 

Para fins de registro, receio que não haja uma maneira mais agradável de fazer isso, mas para construir a string você mesmo:

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

Desculpe, eu esqueci .. p.Value.ToString() deve fazer o trabalho.

Você não pode, porque não gera nenhum SQL.

A consulta parametrizada (aquela em CommandText ) é enviada ao SQL Server como o equivalente de uma instrução preparada. Quando você executa o comando, os parâmetros e o texto da consulta são tratados separadamente. Em nenhum momento uma string SQL completa é gerada.

Você pode usar o SQL Profiler para dar uma olhada nos bastidores.

Eu precisava de um comando semelhante para transformar o transformador em string para permitir um registro mais detalhado, então escrevi este. Ele produzirá o texto necessário para executar novamente o comando em uma nova session, incluindo parâmetros de saída e parâmetros estruturados. É levemente testado, mas emptor de advertência.

Exemplo:

 SqlCommand cmd = new SqlCommand("GetEntity", con); cmd.Parameters.AddWithValue("@foobar", 1); cmd.Parameters.Add(new SqlParameter(){ ParameterName = "@outParam", Direction = ParameterDirection.Output, SqlDbType = System.Data.SqlDbType.Int }); cmd.Parameters.Add(new SqlParameter(){ Direction = ParameterDirection.ReturnValue }); cmd.CommandType = CommandType.StoredProcedure; 

vai produzir:

 -- BEGIN COMMAND DECLARE @foobar INT = 1; DECLARE @outParam INT = NULL; DECLARE @returnValue INT; -- END PARAMS EXEC @returnValue = GetEntity @foobar = @foobar, @outParam = @outParam OUTPUT -- RESULTS SELECT 1 as Executed, @returnValue as ReturnValue, @outParam as [@outParam]; -- END COMMAND 

Implementação:

 public class SqlCommandDumper { public static string GetCommandText(SqlCommand sqc) { StringBuilder sbCommandText = new StringBuilder(); sbCommandText.AppendLine("-- BEGIN COMMAND"); // params for (int i = 0; i < sqc.Parameters.Count; i++) logParameterToSqlBatch(sqc.Parameters[i], sbCommandText); sbCommandText.AppendLine("-- END PARAMS"); // command if (sqc.CommandType == CommandType.StoredProcedure) { sbCommandText.Append("EXEC "); bool hasReturnValue = false; for (int i = 0; i < sqc.Parameters.Count; i++) { if (sqc.Parameters[i].Direction == ParameterDirection.ReturnValue) hasReturnValue = true; } if (hasReturnValue) { sbCommandText.Append("@returnValue = "); } sbCommandText.Append(sqc.CommandText); bool hasPrev = false; for (int i = 0; i < sqc.Parameters.Count; i++) { var cParam = sqc.Parameters[i]; if (cParam.Direction != ParameterDirection.ReturnValue) { if (hasPrev) sbCommandText.Append(", "); sbCommandText.Append(cParam.ParameterName); sbCommandText.Append(" = "); sbCommandText.Append(cParam.ParameterName); if (cParam.Direction.HasFlag(ParameterDirection.Output)) sbCommandText.Append(" OUTPUT"); hasPrev = true; } } } else { sbCommandText.AppendLine(sqc.CommandText); } sbCommandText.AppendLine("-- RESULTS"); sbCommandText.Append("SELECT 1 as Executed"); for (int i = 0; i < sqc.Parameters.Count; i++) { var cParam = sqc.Parameters[i]; if (cParam.Direction == ParameterDirection.ReturnValue) { sbCommandText.Append(", @returnValue as ReturnValue"); } else if (cParam.Direction.HasFlag(ParameterDirection.Output)) { sbCommandText.Append(", "); sbCommandText.Append(cParam.ParameterName); sbCommandText.Append(" as ["); sbCommandText.Append(cParam.ParameterName); sbCommandText.Append(']'); } } sbCommandText.AppendLine(";"); sbCommandText.AppendLine("-- END COMMAND"); return sbCommandText.ToString(); } private static void logParameterToSqlBatch(SqlParameter param, StringBuilder sbCommandText) { sbCommandText.Append("DECLARE "); if (param.Direction == ParameterDirection.ReturnValue) { sbCommandText.AppendLine("@returnValue INT;"); } else { sbCommandText.Append(param.ParameterName); sbCommandText.Append(' '); if (param.SqlDbType != SqlDbType.Structured) { logParameterType(param, sbCommandText); sbCommandText.Append(" = "); logQuotedParameterValue(param.Value, sbCommandText); sbCommandText.AppendLine(";"); } else { logStructuredParameter(param, sbCommandText); } } } private static void logStructuredParameter(SqlParameter param, StringBuilder sbCommandText) { sbCommandText.AppendLine(" {List Type};"); var dataTable = (DataTable)param.Value; for (int rowNo = 0; rowNo < dataTable.Rows.Count; rowNo++) { sbCommandText.Append("INSERT INTO "); sbCommandText.Append(param.ParameterName); sbCommandText.Append(" VALUES ("); bool hasPrev = true; for (int colNo = 0; colNo < dataTable.Columns.Count; colNo++) { if (hasPrev) { sbCommandText.Append(", "); } logQuotedParameterValue(dataTable.Rows[rowNo].ItemArray[colNo], sbCommandText); hasPrev = true; } sbCommandText.AppendLine(");"); } } const string DATETIME_FORMAT_ROUNDTRIP = "o"; private static void logQuotedParameterValue(object value, StringBuilder sbCommandText) { try { if (value == null) { sbCommandText.Append("NULL"); } else { value = unboxNullable(value); if (value is string || value is char || value is char[] || value is System.Xml.Linq.XElement || value is System.Xml.Linq.XDocument) { sbCommandText.Append("N'"); sbCommandText.Append(value.ToString().Replace("'", "''")); sbCommandText.Append('\''); } else if (value is bool) { // True -> 1, False -> 0 sbCommandText.Append(Convert.ToInt32(value)); } else if (value is sbyte || value is byte || value is short || value is ushort || value is int || value is uint || value is long || value is ulong || value is float || value is double || value is decimal) { sbCommandText.Append(value.ToString()); } else if (value is DateTime) { // SQL Server only supports ISO8601 with 3 digit precision on datetime, // datetime2 (>= SQL Server 2008) parses the .net format, and will // implicitly cast down to datetime. // Alternatively, use the format string "yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fffK" // to match SQL server parsing sbCommandText.Append("CAST('"); sbCommandText.Append(((DateTime)value).ToString(DATETIME_FORMAT_ROUNDTRIP)); sbCommandText.Append("' as datetime2)"); } else if (value is DateTimeOffset) { sbCommandText.Append('\''); sbCommandText.Append(((DateTimeOffset)value).ToString(DATETIME_FORMAT_ROUNDTRIP)); sbCommandText.Append('\''); } else if (value is Guid) { sbCommandText.Append('\''); sbCommandText.Append(((Guid)value).ToString()); sbCommandText.Append('\''); } else if (value is byte[]) { var data = (byte[])value; if (data.Length == 0) { sbCommandText.Append("NULL"); } else { sbCommandText.Append("0x"); for (int i = 0; i < data.Length; i++) { sbCommandText.Append(data[i].ToString("h2")); } } } else { sbCommandText.Append("/* UNKNOWN DATATYPE: "); sbCommandText.Append(value.GetType().ToString()); sbCommandText.Append(" *" + "/ N'"); sbCommandText.Append(value.ToString()); sbCommandText.Append('\''); } } } catch (Exception ex) { sbCommandText.AppendLine("/* Exception occurred while converting parameter: "); sbCommandText.AppendLine(ex.ToString()); sbCommandText.AppendLine("*/"); } } private static object unboxNullable(object value) { var typeOriginal = value.GetType(); if (typeOriginal.IsGenericType && typeOriginal.GetGenericTypeDefinition() == typeof(Nullable<>)) { // generic value, unboxing needed return typeOriginal.InvokeMember("GetValueOrDefault", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.InvokeMethod, null, value, null); } else { return value; } } private static void logParameterType(SqlParameter param, StringBuilder sbCommandText) { switch (param.SqlDbType) { // variable length case SqlDbType.Char: case SqlDbType.NChar: case SqlDbType.Binary: { sbCommandText.Append(param.SqlDbType.ToString().ToUpper()); sbCommandText.Append('('); sbCommandText.Append(param.Size); sbCommandText.Append(')'); } break; case SqlDbType.VarChar: case SqlDbType.NVarChar: case SqlDbType.VarBinary: { sbCommandText.Append(param.SqlDbType.ToString().ToUpper()); sbCommandText.Append("(MAX /* Specified as "); sbCommandText.Append(param.Size); sbCommandText.Append(" */)"); } break; // fixed length case SqlDbType.Text: case SqlDbType.NText: case SqlDbType.Bit: case SqlDbType.TinyInt: case SqlDbType.SmallInt: case SqlDbType.Int: case SqlDbType.BigInt: case SqlDbType.SmallMoney: case SqlDbType.Money: case SqlDbType.Decimal: case SqlDbType.Real: case SqlDbType.Float: case SqlDbType.Date: case SqlDbType.DateTime: case SqlDbType.DateTime2: case SqlDbType.DateTimeOffset: case SqlDbType.UniqueIdentifier: case SqlDbType.Image: { sbCommandText.Append(param.SqlDbType.ToString().ToUpper()); } break; // Unknown case SqlDbType.Timestamp: default: { sbCommandText.Append("/* UNKNOWN DATATYPE: "); sbCommandText.Append(param.SqlDbType.ToString().ToUpper()); sbCommandText.Append(" *" + "/ "); sbCommandText.Append(param.SqlDbType.ToString().ToUpper()); } break; } } } 

Se você estiver usando o SQL Server, poderá usar o SQL Server Profiler (se tiver) para exibir a cadeia de comando que é realmente executada. Isso seria útil para purpuses de teste de copiar / colar, mas não para log estou com medo.

Eu também tive este problema onde algumas consultas parametrizadas ou sp’s me davam uma SqlException (a maioria das strings ou dados binários seriam truncados), e as declarações eram difíceis de depurar (Até onde eu sei, atualmente não há suporte a sql-profiler para SQL Azure)

Eu vejo muito código simular em reações aqui. Acabei colocando minha solução em um projeto de biblioteca de Sql para uso futuro.

O gerador está disponível aqui: https://github.com/jeroenpot/SqlHelper/blob/master/Source/Mirabeau.MsSql.Library/SqlGenerator.cs

Suporta CommandType.Text e CommandType.StoredProcedure

E se você instalar o pacote nuget, você pode gerá-lo com esta declaração:

 SqlDebugHelper.CreateExecutableSqlStatement(sql, parameters); 

O Profiler é a sua melhor opção.

Pode ser necessário copiar um conjunto de instruções do profiler devido às etapas prepare + execute envolvidas.

Usado parte do código do Flapper para minha solução, que retorna toda a string SQL incluindo valores de parâmetros para executar no MS SQL SMS.

 public string ParameterValueForSQL(SqlParameter sp) { string retval = ""; switch (sp.SqlDbType) { case SqlDbType.Char: case SqlDbType.NChar: case SqlDbType.NText: case SqlDbType.NVarChar: case SqlDbType.Text: case SqlDbType.Time: case SqlDbType.VarChar: case SqlDbType.Xml: case SqlDbType.Date: case SqlDbType.DateTime: case SqlDbType.DateTime2: case SqlDbType.DateTimeOffset: if (sp.Value == DBNull.Value) { retval = "NULL"; } else { retval = "'" + sp.Value.ToString().Replace("'", "''") + "'"; } break; case SqlDbType.Bit: if (sp.Value == DBNull.Value) { retval = "NULL"; } else { retval = ((bool)sp.Value == false) ? "0" : "1"; } break; default: if (sp.Value == DBNull.Value) { retval = "NULL"; } else { retval = sp.Value.ToString().Replace("'", "''"); } break; } return retval; } public string CommandAsSql(SqlCommand sc) { string sql = sc.CommandText; sql = sql.Replace("\r\n", "").Replace("\r", "").Replace("\n", ""); sql = System.Text.RegularExpressions.Regex.Replace(sql, @"\s+", " "); foreach (SqlParameter sp in sc.Parameters) { string spName = sp.ParameterName; string spValue = ParameterValueForSQL(sp); sql = sql.Replace(spName, spValue); } sql = sql.Replace("= NULL", "IS NULL"); sql = sql.Replace("!= NULL", "IS NOT NULL"); return sql; } 

Se for apenas para verificar como um parâmetro é formatado na consulta de resultado, a maioria dos SGBDs permitirá a consulta de literais a partir do nada. Portanto:

 Using cmd As SqlCommand = Connection.CreateCommand cmd.CommandText = "SELECT @Value" cmd.Parameters.AddWithValue("@Value", "myValue") Return cmd.ExecuteScalar End Using 

Dessa forma, você pode ver se as cotações são duplicadas, etc.

Isso é o que eu uso para gerar listas de parâmetros para um procedimento armazenado no console de debugging:

 string query = (from SqlParameter p in sqlCmd.Parameters where p != null where p.Value != null select string.Format("Param: {0} = {1}, ", p.ParameterName, p.Value.ToString())).Aggregate(sqlCmd.CommandText, (current, parameter) => current + parameter); Debug.WriteLine(query); 

Isso gerará uma saída do console semelhante a isto:

 Customer.prGetCustomerDetails: @Offset = 1, Param: @Fetch = 10, Param: @CategoryLevel1ID = 3, Param: @VehicleLineID = 9, Param: @SalesCode1 = bce, 

Eu coloco este código diretamente abaixo de qualquer procedimento que eu queira depurar e é semelhante a uma session do SQL Profiler, mas em C #.

Versão modificada da resposta de Kon, pois funciona apenas parcialmente com parâmetros nomeados semelhantes. O lado negativo da function String Replace. Fora isso, dou a ele crédito total pela solução.

  private string GetActualQuery(SqlCommand sqlcmd) { string query = sqlcmd.CommandText; string parameters = ""; string[] strArray = System.Text.RegularExpressions.Regex.Split(query, " VALUES "); //Reconstructs the second half of the SQL Command parameters = "("; int count = 0; foreach (SqlParameter p in sqlcmd.Parameters) { if (count == (sqlcmd.Parameters.Count - 1)) { parameters += p.Value.ToString(); } else { parameters += p.Value.ToString() + ", "; } count++; } parameters += ")"; //Returns the string recombined. return strArray[0] + " VALUES " + parameters; } 

Minha solução:

 public static class DbHelper { public static string ToString(this DbParameterCollection parameters, string sqlQuery) { return parameters.Cast().Aggregate(sqlQuery, (current, p) => current.Replace(p.ParameterName, p.Value.ToString())); } } 

Esta solução funciona para mim agora. Talvez seja útil para alguém. Por favor, desculpe toda a redundância.

  Public Shared Function SqlString(ByVal cmd As SqlCommand) As String Dim sbRetVal As New System.Text.StringBuilder() For Each item As SqlParameter In cmd.Parameters Select Case item.DbType Case DbType.String sbRetVal.AppendFormat("DECLARE {0} AS VARCHAR(255)", item.ParameterName) sbRetVal.AppendLine() sbRetVal.AppendFormat("SET {0} = '{1}'", item.ParameterName, item.Value) sbRetVal.AppendLine() Case DbType.DateTime sbRetVal.AppendFormat("DECLARE {0} AS DATETIME", item.ParameterName) sbRetVal.AppendLine() sbRetVal.AppendFormat("SET {0} = '{1}'", item.ParameterName, item.Value) sbRetVal.AppendLine() Case DbType.Guid sbRetVal.AppendFormat("DECLARE {0} AS UNIQUEIDENTIFIER", item.ParameterName) sbRetVal.AppendLine() sbRetVal.AppendFormat("SET {0} = '{1}'", item.ParameterName, item.Value) sbRetVal.AppendLine() Case DbType.Int32 sbRetVal.AppendFormat("DECLARE {0} AS int", item.ParameterName) sbRetVal.AppendLine() sbRetVal.AppendFormat("SET {0} = {1}", item.ParameterName, item.Value) sbRetVal.AppendLine() Case Else Stop End Select Next sbRetVal.AppendLine("") sbRetVal.AppendLine(cmd.CommandText) Return sbRetVal.ToString() End Function 

Eu tive a mesma pergunta exata e depois de ler essas respostas, decidi erroneamente que não era possível obter a consulta resultante exata. Eu estava errado.

Solução: Abra o Activity Monitor no SQL Server Management Studio , restrinja a seção de processos ao nome de usuário de login, database ou nome do aplicativo que o aplicativo está usando na cadeia de conexão. Quando a chamada é feita para o Activity Monitor atualização do database. Quando você vê o processo, clique com o botão direito nele e View Details .

Note, isso pode não ser uma opção viável para um database ocupado. Mas você deve poder reduzir consideravelmente o resultado usando essas etapas.

Como @pkExec e @Alok mencionado, o uso de Substituir não funciona em 100% dos casos. Essa é a solução que usei em nosso DAL que usa o RegExp para “corresponder somente palavra inteira” e formata os tipos de dados corretamente. Assim, o SQL gerado pode ser testado diretamente no MySQL Workbench (ou SQLSMS, etc …) 🙂

(Substitua a function MySQLHelper.EscapeString () de acordo com o DBMS usado.)

 Dim query As String = cmd.CommandText query = query.Replace("SET", "SET" & vbNewLine) query = query.Replace("WHERE", vbNewLine & "WHERE") query = query.Replace("GROUP BY", vbNewLine & "GROUP BY") query = query.Replace("ORDER BY", vbNewLine & "ORDER BY") query = query.Replace("INNER JOIN", vbNewLine & "INNER JOIN") query = query.Replace("LEFT JOIN", vbNewLine & "LEFT JOIN") query = query.Replace("RIGHT JOIN", vbNewLine & "RIGHT JOIN") If query.Contains("UNION ALL") Then query = query.Replace("UNION ALL", vbNewLine & "UNION ALL" & vbNewLine) ElseIf query.Contains("UNION DISTINCT") Then query = query.Replace("UNION DISTINCT", vbNewLine & "UNION DISTINCT" & vbNewLine) Else query = query.Replace("UNION", vbNewLine & "UNION" & vbNewLine) End If For Each par In cmd.Parameters If par.Value Is Nothing OrElse IsDBNull(par.Value) Then query = RegularExpressions.Regex.Replace(query, par.ParameterName & "\b", "NULL") ElseIf TypeOf par.Value Is Date Then query = RegularExpressions.Regex.Replace(query, par.ParameterName & "\b", "'" & Format(par.Value, "yyyy-MM-dd HH:mm:ss") & "'") ElseIf TypeOf par.Value Is TimeSpan Then query = RegularExpressions.Regex.Replace(query, par.ParameterName & "\b", "'" & par.Value.ToString & "'") ElseIf TypeOf par.Value Is Double Or TypeOf par.Value Is Decimal Or TypeOf par.Value Is Single Then query = RegularExpressions.Regex.Replace(query, par.ParameterName & "\b", Replace(par.Value.ToString, ",", ".")) ElseIf TypeOf par.Value Is Integer Or TypeOf par.Value Is UInteger Or TypeOf par.Value Is Long Or TypeOf par.Value Is ULong Then query = RegularExpressions.Regex.Replace(query, par.ParameterName & "\b", par.Value.ToString) Else query = RegularExpressions.Regex.Replace(query, par.ParameterName & "\b", "'" & MySqlHelper.EscapeString(CStr(par.Value)) & "'") End If Next 

Exemplo:

 SELECT * FROM order WHERE order_status = @order_status AND order_date = @order_date 

Será gerado:

 SELECT * FROM order WHERE order_status = 'C' AND order_date = '2015-01-01 00:00:00' 

as consultas do comando sql serão executadas com exec sp_executesql, então aqui está outra maneira de obter a instrução como uma string (método de extensão SqlCommand):

 public static string ToSqlStatement(this SqlCommand cmd) { return $@"EXECUTE sp_executesql N'{cmd.CommandText.Replace("'", "''")}'{cmd.Parameters.ToSqlParameters()}"; } private static string ToSqlParameters(this SqlParameterCollection col) { if (col.Count == 0) return string.Empty; var parameters = new List(); var parameterValues = new List(); foreach (SqlParameter param in col) { parameters.Add($"{param.ParameterName}{param.ToSqlParameterType()}"); parameterValues.Add($"{param.ParameterName} = {param.ToSqlParameterValue()}"); } return $",N\'{string.Join(",", parameters)}\',{string.Join(",", parameterValues)}"; } private static object ToSqlParameterType(this SqlParameter param) { var paramDbType = param.SqlDbType.ToString().ToLower(); if (param.Precision != 0 && param.Scale != 0) return $"{paramDbType}({param.Precision},{param.Scale})"; if (param.Precision != 0) return $"{paramDbType}({param.Precision})"; switch (param.SqlDbType) { case SqlDbType.VarChar: case SqlDbType.NVarChar: string s = param.SqlValue?.ToString() ?? string.Empty; return paramDbType + (s.Length > 0 ? $"({s.Length})" : string.Empty); default: return paramDbType; } } private static string ToSqlParameterValue(this SqlParameter param) { switch (param.SqlDbType) { case SqlDbType.Char: case SqlDbType.Date: case SqlDbType.DateTime: case SqlDbType.DateTime2: case SqlDbType.DateTimeOffset: case SqlDbType.NChar: case SqlDbType.NText: case SqlDbType.NVarChar: case SqlDbType.Text: case SqlDbType.Time: case SqlDbType.VarChar: case SqlDbType.Xml: return $"\'{param.SqlValue.ToString().Replace("'", "''")}\'"; case SqlDbType.Bit: return param.SqlValue.ToBooleanOrDefault() ? "1" : "0"; default: return param.SqlValue.ToString().Replace("'", "''"); } } public static bool ToBooleanOrDefault(this object o, bool defaultValue = false) { if (o == null) return defaultValue; string value = o.ToString().ToLower(); switch (value) { case "yes": case "true": case "ok": case "y": return true; case "no": case "false": case "n": return false; default: bool b; if (bool.TryParse(o.ToString(), out b)) return b; break; } return defaultValue; } 

Um forro:

 string.Join(",", from SqlParameter p in cmd.Parameters select p.ToString()) 

Eu escrevi esse método para mim. Eu uso alguma parte do código de Bruno Ratnieks . Talvez seja útil para alguém.

  public static string getQueryFromCommand(SqlCommand cmd) { StringBuilder CommandTxt = new StringBuilder(); CommandTxt.Append("DECLARE "); List paramlst = new List(); foreach (SqlParameter parms in cmd.Parameters) { paramlst.Add(parms.ParameterName); CommandTxt.Append(parms.ParameterName + " AS "); CommandTxt.Append(parms.SqlDbType.ToString()); CommandTxt.Append(","); } if (CommandTxt.ToString().Substring(CommandTxt.Length-1, 1) == ",") CommandTxt.Remove(CommandTxt.Length-1, 1); CommandTxt.AppendLine(); int rownr = 0; foreach (SqlParameter parms in cmd.Parameters) { string val = String.Empty; if (parms.DbType.Equals(DbType.String) || parms.DbType.Equals(DbType.DateTime)) val = "'" + Convert.ToString(parms.Value).Replace(@"\", @"\\").Replace("'", @"\'") + "'"; if (parms.DbType.Equals(DbType.Int16) || parms.DbType.Equals(DbType.Int32) || parms.DbType.Equals(DbType.Int64) || parms.DbType.Equals(DbType.Decimal) || parms.DbType.Equals(DbType.Double)) val = Convert.ToString(parms.Value); CommandTxt.AppendLine(); CommandTxt.Append("SET " + paramlst[rownr].ToString() + " = " + val.ToString()); rownr += 1; } CommandTxt.AppendLine(); CommandTxt.AppendLine(); CommandTxt.Append(cmd.CommandText); return CommandTxt.ToString(); }