C# 有没有一个简单的方法来获得;sp_executesql";NET为参数化查询生成的查询?

C# 有没有一个简单的方法来获得;sp_executesql";NET为参数化查询生成的查询?,c#,sql,.net,.net-4.5,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()) {

背景:

如果我有以下程序

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中是否有一些类或函数已经执行了我忽略的这个操作


如果我能够访问参数的名称,那么编写解析器将非常容易,但我觉得在生产应用程序中使用反射来访问.NET framework的未发布内部API是不可能的。

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

即使在SQL Server中,您也可以使用诸如sp_prepare之类的命令来准备SQL查询,但它不会返回文本。相反,它返回一个带参数的已编译查询句柄。我可以想象,通过一点调查,您可以找到已编译查询的位置,但是使用SQL Server为您执行此类工作是没有效率的。只有当您能够返回已编译的查询并恢复到语句时,才能这样做


在旧版本的SQL Server中,可以使用sp_helptext从系统存储过程中提取文本,但它不再起作用。它可以向您展示它们是如何做到这一点的,但这并不比构建您自己的解析器更好。

尝试从SQL和参数创建字符串会使初始的、好的查询方法变得不好

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


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

格雷戈里的回答有点正确,但大部分是不正确的。是的,没有可以调用的
public
方法来获取此信息,但是有
private
方法(您不能调用)这确实将
CommandText
SqlParameterCollection
重新打包为对
sp_executesql
的存储过程调用,并将参数名和数据类型的预格式化列表作为该存储过程的第二个输入参数(请参阅下面关于
BuildParamList
的说明)

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

  • Microsoft.com上的原始代码,网址:
  • GitHub.com上的.NET核心版本,网址:
似乎您需要的主要内容是
BuildParamList
方法(当然,还有它调用的任何方法):


那么您想获取从
SqlCommand
对象运行的字符串吗?似乎做一个
string.Format()
来获得原始SQL字符串是很容易的…@DLeh我同意,这就是为什么我说我可以自己做的原因。唯一需要技巧的部分是正确翻译
参数.DbType
参数.Size
参数.Scale
。这就是为什么我想知道.NET是否有机会为我这样做,这样我就不需要编写转换。请尝试此链接,除非您所说的内容与sql Server profiler中捕获的内容相同-@MethodMan不,我实际上需要参数。这将用于在数据库中存储一组查询,然后在以后执行。目前,所有查询都是非参数化的(使用与链接中的答案类似的技术)。我的目标是能够以参数化的形式执行查询,以帮助利用SQL中的计划缓存之类的东西。我并没有试图“去参数化”查询。我的问题是,有没有一种简单的方法来建立由.NET代码生成的
sp_executesql
调用。具体来说,如果有一种简单的方法可以生成需要传递到
@params
参数中的类型,而无需手动编码每个可能的Sql数据类型。基本上,有没有一种方法可以在不进行反射的情况下获得Ohh的值,当.NET内核发布后,我并没有考虑重新访问它。@ScottChamberlain我只是更新了我的答案来澄清一些事情。但是,即使没有GitHub上的项目,您仍然可以获得所需的信息,以确信您的代码能够正常运行:)。