从.NET中,我是否可以获取由SqlCommand对象(带有SQL参数)生成的完整SQL字符串?
从.NET中,我是否可以获取由SqlCommand对象(带有SQL参数)生成的完整SQL字符串?
在.NET环境下,我能否访问由 SqlCommand 对象生成的完整SQL字符串?
注意:在调试模式下,完整的SQL字符串会在Intellisense悬停中显示在VisualStudio中。
如果必须,我愿意使用反射技术。我相信这里有人知道如何访问它。
更新1:
我正在调用具有参数的存储过程 cmd.CommandType = CommandType.StoredProcedure
,并尝试获取生成和运行的完整SQL。
我想知道如果cmd. Prepare()
方法在此情况下是否有用,如果它可以将完整字符串存储在状态字段或类似的内容中。
更新2:
鉴于下面(和引用)的答案表明在准备或执行期间没有生成完整的SQL字符串,我使用.NET反编译器进行了一些探索。即使是内部连接类似乎也传递对象,而不是将它们化作字符串,例如:
internal abstract void AddPreparedCommand(SqlCommand cmd);
声明类型:System.Data.SqlClient.SqlInternalConnection
程序集:System.Data,版本=2.0.0.0
总的来说,感谢每个人提供的详细信息,证明了可以做什么,并展示了实际发生的事情。非常感谢。我喜欢详细的解释;它们增加了可靠性并给答案增加了可信度。
这里已经有一些类似的问题了。
最有说服力的答案是回答了这个问题:如何从SqlCommand对象中获取生成的SQL语句?
答案是:
你不能获取,因为它并不会生成任何SQL语句。
参数化查询(CommandText中的查询)被发送到SQL Server作为预处理语句的等效项。当你执行命令时,参数和查询文本被分别处理。在任何时候都没有生成完整的SQL字符串。
你可以使用SQL Profiler来查看背后的情况。
一项简单的循环操作将所有参数名称替换为其值,将提供类似于最终结果的内容,但是存在几个问题:\n
- \n
- 由于SQL实际上从未使用参数值重建,因此无需考虑换行符和引号等内容。
- 注释中的参数名称实际上从未被处理其值,而是保留不变。
\n
\n
\n有了这些,再考虑以相同字符开头的参数名称,例如@NAME
和@NAME_FULL
,我们可以使用该参数的值替换所有参数名称,该值将处于该参数的位置:\n
string query = cmd.CommandText; foreach (SqlParameter p in cmd.Parameters.OrderByDescending(p => p.ParameterName.Length)) { query = query.Replace(p.ParameterName, p.Value.ToString()); }
\n然而,这里还有一个问题,即如果一个参数是字符串,那么最初的SQL将如下所示:\n
SELECT * FROM yourtable WHERE table_code = @CODE
\n将会变为:\n
SELECT * FROM yourtable WHERE table_code = SOME CODE WITH SPACES
\n这显然不是合法的SQL,因此我们还需要考虑某些参数类型:\n
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); }