是否有一种简单的方法来获取.NET为参数化查询生成的“sp_executesql”查询?

时间:2015-03-19 19:43:59

标签: c# sql .net .net-4.5

背景

如果我有以下程序

public class Program
{
    public static void Main()
    {
        using(var connection = new SqlConnection("Server=(local);Database=Testing;Trusted_Connection=True"))
        using (var command = connection.CreateCommand())
        {
            connection.Open();
            command.CommandText = "UPDATE Foo set Bar = @Text";
            command.Parameters.Add("@Text", SqlDbType.VarChar, 50).Value = "Hello World!";
            command.ExecuteNonQuery();
        }
    }
}

执行时,运行以下查询(根据SQL Server Profiler)

exec sp_executesql N'UPDATE Foo set Bar = @Text',N'@Text varchar(50)',@Text='Hello World!'

我的问题:

我想做的是,如果我有以下

command.CommandText = "UPDATE Foo set Bar = @Text";
command.Parameters.Add("@Text", SqlDbType.VarChar, 50).Value = "Hello World!";
string query = GenerateQuery(command);

GenerateQuery将返回字符串

"exec sp_executesql N'UPDATE Foo set Bar = @Text',N'@Text varchar(50)',@Text='Hello World!'"

我能够编写一个解析器来遍历Parameters集合中的每个参数并构建字符串。但是,在我开始从头开始编写这个解析器之前,.NET中是否有一些类或函数已经执行了我忽略的操作?

如果我有权访问参数的MetaType,那么解析器将非常简单,但我觉得使用生成应用程序中的反射来访问.NET框架的未发布的内部API是不可能的。< / p>

3 个答案:

答案 0 :(得分:3)

格雷戈里的答案有点正确,但大多不正确。是的,没有public方法你可以调用来获得这个,但是有private个方法(你无法调用)确实重新打包CommandText和{{ 1}}作为对SqlParameterCollection的存储过程调用,使用预格式化的参数名称和数据类型列表作为该存储过程的第二个输入参数(请参阅下面有关sp_executesql的注释)。

虽然这是Microsoft源代码,但代码也是开源.NET Core项目的一部分,该项目主要在MIT license下发布。意思是,您可以复制并粘贴您需要的部件:-)。即使代码仅在referencesource.microsoft.com上,您仍然可以从中了解您的需求,并使用它来验证您的版本在功能上与它一致。

您需要的主要内容似乎是BuildParamList方法(当然,无论它调用什么):

答案 1 :(得分:1)

目前,这里什么都没有。命令对象将参数化文本和所有参数发送到SQL Server,然后SQL Server使用sp_executesql存储过程将它们结合在一起。 SQL Server .NET对象中没有任何内容可以使用参数解析查询,因此您无法提取在SQL Server上运行的内容。

即使在SQL Server中,您也有像sp_prepare这样的命令,它们将准备SQL查询,但它不会返回文本。相反,它返回带有参数的已编译查询的句柄。我想,通过一些调查,您可以找到编译查询的位置,但使用SQL Server为您执行此类工作效率不高。这只是因为您可以返回已编译的查询并恢复到该语句。

在旧版本的SQL Server中,您可以使用sp_helptext从系统sprocs中提取文本,但它不再起作用。它可以告诉你他们是如何做到的,但它不会比构建你自己的解析器更好。

答案 2 :(得分:-1)

尝试从SQL和参数创建字符串会使初始的,良好的查询方法变坏。

sp_executesql在SQL Server上创建参数化查询,并在重复调用具有相同的SQL字符串和签名(但可能是不同的参数值)时重新使用查询计划。带有sp_executesql的SQL事件探查器输出实际上是这样发送的;它可以在SSMS中复制和执行。将参数值连接到SQL字符串将为每个调用创建一个新的查询和查询计划,就像它在开始时已连接一样(包括性能损失和SQL注入风险)。

在我看来,ADO.NET中的sp_prepare和DbCommand.Prepare()已经过时,因为应用程序必须保持查询的句柄,并且只能在有限的范围内使用它(连接),而sp_executesql重用每当SQL和签名字符串(参数名称和类型)相等时,查询计划,无论应用程序如何获取它们。

相关问题