【问题标题】:How to override SqlCommand to grab generated TSQL如何重写 SqlCommand 以获取生成的 TSQL
【发布时间】:2017-08-22 03:41:30
【问题描述】:

有什么方法可以拦截SqlCommand 生成的SQL 吗?

我目前有一个方法可以执行存储过程:

public int ExecSP(string spName, params objec[] params)
{
     using (SqlConnection con = new SqlConnection("AdventureWorks")) 
     using (SqlCommand cmd = new SqlCommand(spName, con)) 
     {
         cmd.CommandType = CommandType.StoredProcedure;

        //..calls method to add params and values to cmd object

        con.Open();
        return cmd.ExecuteNonQuery();
     }
}

当我使用它来调用以下内容时:

ExecSP("HumanResources.uspUpdateEmployeePersonalInfo", 1, "295847284", new DateTime(1963, 3, 2), "S", "M");`

我在 SQLProfiler 中得到以下信息:

exec HumanResources.uspUpdateEmployeePersonalInfo @BusinessEntityID=1,@NationalIDNumber=N'295847284',@BirthDate='1963-03-02 00:00:00',@MaritalStatus=N'S',@Gender=N'M'

我想做的是截取那个 SQL 命令,这样我就可以在它的末尾添加一个包含一些相关信息的注释,使它看起来像:

exec HumanResources.uspUpdateEmployeePersonalInfo @BusinessEntityID=1,@NationalIDNumber=N'295847284',@BirthDate='1963-03-02 00:00:00',@MaritalStatus=N'S',@Gender=N'M' -- IMPORTANT INFORMATION HERE

我无法将 CommandType 更改为 Text,也无法向存储过程添加额外的参数。我尝试查看这些其他问题,但没有运气:

Can I override SqlCommand functions?

SqlCommand to T-SQL

【问题讨论】:

  • 我什么都不知道,但可以在网上找到源代码。您可以创建自己的版本并使用它来完成此操作。
  • 我希望尽可能避免这种情况,因为创建自定义版本可能会带来意想不到的错误。不过还是谢谢。
  • 可能重复我的一个老问题stackoverflow.com/questions/29153589/…
  • @ScottChamberlain 是的,这非常相似。感谢您的链接。你能实现它吗?
  • 没有。由于编写解析器的时间问题,我们采用了不同的方法。项目完成几个月后,得到了接受的答案。

标签: c# sql-server ado.net sqlcommand sql-server-profiler


【解决方案1】:

对于CommandType = CommandType.StoredProcedure,这是不可能的。

为什么?您在 SQL Profiler 中看到的 SQL 不是由客户端生成的。 :-/

当 SqlCommand 执行 CommandType.StoredProcedure 命令时,它会向 SQL Server 发送带有存储过程名称和包含参数的数据结构的 execute remote procedure call message

TextData SQL Profiler 显示的RPC:Starting/RPC:Completed 事件是在服务器端生成的。由于此文本不是在客户端生成的,因此无法在客户端对其进行修改。

【讨论】:

  • 这很不幸。您是否会碰巧知道是否有任何文档可以让我阅读有关此内容的信息?谢谢。
  • CommandType.Text 或 CommandType.TableDirect 也不可能。
  • 使用 CommandType.Text 我只会将信息附加到查询中,因为它只是一个 sql 注释,并且工作正常。我只是想不将 CommandType.StoredProcedure 更改为 CommandType.Text
  • 嗨@ODot,有关文档,请查看 TDS 如何定义其RPC Request。注意过程名称(或特殊过程 ID)如何包含在调用中,但没有传递 T-SQL 命令文本。
【解决方案2】:

您看到的是调试/配置文件消息,但这并不能完全代表实际执行的内容(数据库将在幕后使用sp_executesql())。

您要查找的内容不存在。使用参数对象的全部意义在于参数值是从不在任何时候,作为sql命令字符串的一部分,甚至在服务器上 em>。

这完成了三个主要的事情:

  1. 它可以防止任何可能通过该查询进行 sql 注入攻击。您将永远遇到一些奇怪的 unicode 字符集问题,允许攻击者将命令插入到您的查询数据中,例如 they did a couple years back with php/mysql,或者一些新的语言功能会造成您的旧的转义码不够好。在每个阶段,查询的用户数据部分总是与查询的命令逻辑部分分开。
  2. 它通过允许服务器缓存执行计划来提高性能。这样可以节省编译步骤,因为您的应用程序会一遍又一遍地执行相同的查询,只是使用不同的参数数据。
  3. 它避免了诸如日期、带撇号的文本数据等格式的问题。

如果要获取调试数据,请编写一个方法来输出查询和随之而来的参数数据。如果您想在您的个人资料跟踪中添加信息,您可以切换到CommandType.Text 并通过您自己的EXEC procedurename @param1, @param2, ... @paramN -- INFO HERE 字符串调用存储过程。

【讨论】:

  • 嗨@Joel Coehoorn!当您说“数据库将在幕后使用 sp_executesql()”时,对于 CommandType = CommandType.CommandText 查询使用参数而不是 CommandType - CommandType.StoredProcedure (如 OP 的问题)不是这样吗?或者,你是说数据库接受TDS RPC请求(包头类型0x03),然后转换成T-SQL然后调用sp_executesql()??
猜你喜欢
  • 2010-09-20
  • 1970-01-01
  • 2020-10-22
  • 1970-01-01
  • 1970-01-01
  • 2014-10-05
  • 2011-05-04
  • 1970-01-01
  • 2010-10-21
相关资源
最近更新 更多