SqlPipe 对象

在以前版本的 SQL Server 中,通过编写存储过程(或扩展存储过程)将结果或输出参数发送到调用客户端的情况非常常见。

在 Transact-SQL 存储过程中,任何 SELECT 返回零行或多行的语句会将结果发送到连接的调用者的“管道”。

对于在 SQL Server 中运行的公共语言运行时 (CLR) 数据库对象,可以使用 对象的 方法SqlPipe将结果发送到连接的管道Send。 访问 Pipe 对象的 SqlContext 属性可以获取 SqlPipe 对象。 从概念上来说,SqlPipe 类与 ASP.NET 中的 Response 类相似。 有关详细信息,请参阅 .NET Framework 软件开发包中的 SqlPipe 类参考文档。

返回表格结果和消息

SqlPipe 包含 Send 方法,该方法具有三次重载。 它们是:

  • void Send(string message)

  • void Send(SqlDataReader reader)

  • void Send(SqlDataRecord record)

Send 方法将数据直接发送到客户端或调用方。 通常是客户端使用来自 SqlPipe 的输出,但在嵌套 CLR 存储过程的情况下,输出使用者也可以是存储过程。 例如,Procedure1 使用命令文本“EXEC Procedure2”调用 SqlCommand.ExecuteReader()。 Procedure2 也是托管存储过程。 如果现在 Procedure2 调用 SqlPipe.Send(SqlDataRecord),则该行被发送到 Procedure1 的读取器,而不是客户端。

方法 Send 发送一条字符串消息,该消息作为信息消息显示在客户端上,等效于 Transact-SQL 中的 PRINT。 该方法还可以使用 SqlDataRecord 发送单行结果集,或者使用 SqlDataReader 发送多行结果集。

SqlPipe 对象还具有 ExecuteAndSend 方法。 可以使用此方法执行作为 SqlCommand 对象传递的命令,并将结果直接回发给调用方。 如果已提交的命令中有错误,则将异常发送到管道,但同时将一个副本发送到调用托管代码。 如果调用代码未捕获异常,它将堆栈向上传播到 Transact-SQL 代码,并在输出中出现两次。 如果调用代码捕获了异常,则管道使用者仍将看到错误,但不会有重复错误。

该方法仅采用与上下文连接关联的 SqlCommand;但不能采用与非上下文连接关联的命令。

返回自定义结果集

托管存储过程可以发送并非来自于 SqlDataReader 的结果集。 SendResultsStart 方法以及 SendResultsRowSendResultsEnd 允许存储过程将自定义结果集发送到客户端。

SendResultsStart 采用 SqlDataRecord 作为输入。 该方法标记结果集的开始,并使用记录元数据构造描述结果集的元数据。 它不会使用 SendResultsStart 发送记录的值。 使用 SendResultsRow 发送的所有后续行都必须与该元数据定义相匹配。

注意

在调用 SendResultsStart 方法之后,只能调用 SendResultsRowSendResultsEnd。 在同一 SqlPipe 实例中调用任何其他方法将导致 InvalidOperationExceptionSendResultsEndSqlPipe 设置回初始状态,您可以在该状态下调用其他方法。

示例

uspGetProductLine 存储过程返回指定产品系列中所有产品的名称、产品编号、颜色和标价。 此存储过程接受 prodLine 的完全匹配项。

C#

using System;  
using System.Data;  
using System.Data.SqlClient;  
using System.Data.SqlTypes;  
using Microsoft.SqlServer.Server;  
  
public partial class StoredProcedures  
{  
[Microsoft.SqlServer.Server.SqlProcedure]  
public static void uspGetProductLine(SqlString prodLine)  
{  
    // Connect through the context connection.  
    using (SqlConnection connection = new SqlConnection("context connection=true"))  
    {  
        connection.Open();  
  
        SqlCommand command = new SqlCommand(  
            "SELECT Name, ProductNumber, Color, ListPrice " +  
            "FROM Production.Product " +   
            "WHERE ProductLine = @prodLine;", connection);  
  
        command.Parameters.AddWithValue("@prodLine", prodLine);  
  
        try  
        {  
            // Execute the command and send the results to the caller.  
            SqlContext.Pipe.ExecuteAndSend(command);  
        }  
        catch (System.Data.SqlClient.SqlException ex)  
        {  
            // An error occurred executing the SQL command.  
        }  
     }  
}  
};  

Visual Basic

Imports System  
Imports System.Data  
Imports System.Data.SqlClient  
Imports System.Data.SqlTypes  
Imports Microsoft.SqlServer.Server  
  
Partial Public Class StoredProcedures  
<Microsoft.SqlServer.Server.SqlProcedure()> _  
Public Shared Sub uspGetProductLine(ByVal prodLine As SqlString)  
    Dim command As SqlCommand  
  
    ' Connect through the context connection.  
    Using connection As New SqlConnection("context connection=true")  
        connection.Open()  
  
        command = New SqlCommand( _  
        "SELECT Name, ProductNumber, Color, ListPrice " & _  
        "FROM Production.Product " & _  
        "WHERE ProductLine = @prodLine;", connection)  
        command.Parameters.AddWithValue("@prodLine", prodLine)  
  
        Try  
            ' Execute the command and send the results   
            ' directly to the caller.  
            SqlContext.Pipe.ExecuteAndSend(command)  
        Catch ex As System.Data.SqlClient.SqlException  
            ' An error occurred executing the SQL command.  
        End Try  
    End Using  
End Sub  
End Class  

以下 Transact-SQL 语句执行 uspGetProduct 过程,该过程返回旅游自行车产品的列表。

EXEC uspGetProductLineVB 'T';  

另请参阅

SqlDataRecord 对象
CLR 存储过程
SQL Server 进程内专用的 ADO.NET 扩展