SQL Server 2005 - 如何從 CLR 預存程序傳回表格結果與訊息(上)

摘要:SQL Server 2005 - 如何從 CLR 預存程序傳回表格結果與訊息(上)

親愛的朋友們閱讀過實作CLR預存程序一文之後,相信大家對於如何建立 CLR 預存程序已經有了清楚的認識。在本文中,我們要繼續討論一個非常重要的課題,那就是如何從 CLR 預存程序傳回表格結果與訊息。

除了透過輸出參數傳回資料之外,我們還可以使用 SqlPipe 物件將表格結果與訊息傳回給用戶端。一般來說,我們是透過 SqlContext 類別的 Pipe 屬性取得 SqlPipe 物件,然後呼叫 SqlPipe 物件的 Send 方法將表格結果或訊息傳送給用戶端。

SqlPipe 物件的 Send 方法擁有下列三個多載版本:
 

q  SqlPipe.Send(message As String)

此多載版本的 Send 方法能夠將字串訊息直接傳送至用戶端。文字訊息最長不可超過 8000 個字元,超出 8000 個字元的部分將會被截掉。

訊息字串會被當作一個資訊訊息傳送給用戶端,至於用戶端要透過哪一種機制來聆聽此訊息,則視用戶端所採用的資料存取應用程式介面(API)而定。比方說,假設用戶端使用 ADO.NET,則訊息會透過事件 InfoMessage 來傳送。 

q  SqlPipe.Send(record As SqlDataRecord)

此多載版本的 Send 方法能夠將單一資料列結果集(也就是一個 SqlDataRecord 物件)直接傳送至用戶端。如果您於 Send 方法中所使用的 SqlDataReader 物件擁有隱藏欄位,這些欄位將不會填入傳送給用戶端的結果集當中。

以前一篇文章所建立的CLR預存程序 SayHello 而言,它除了使用輸出參數來傳回文字資料之外,還呼叫此多載版本的 Send 方法將單一資料列結果集直接傳送至用戶端,如下所示:

SqlContext.Pipe.Send(greetingRecord)

q  SqlPipe.Send(reader As SqlDataReader)

此多載版本的 Send 方法能夠將一個多資料列結果集(也就是一個 SqlDataReader 物件)直接傳送至用戶端。

如果您要傳送先前透過同處理序(In-Process)提供者所執行的查詢結果,或是想要使用 SqlDataReader 的自訂實作來預先處理資料,請使此多載版本的 Send 方法來接收一個 SqlDataReader 物件並將其直接傳送給用戶端。雖然 Send 方法的執行效率稍稍慢於ExecuteAndSend 方法,不過在資料被傳送至用戶端之前,它提供了最大的彈性來處理資料。 

請大家注意,除了使用 Send 方法之外,CLR 預存程序還可以使用 SqlPipe 物件的 ExecuteAndSend 方法將查詢結果傳送給用戶端。ExecuteAndSend 方法的最大好處,就是它提供了一種最高效率的方式將查詢結果傳送給用戶端,之所以如此,是因為資料是透過網路緩衝區來傳送,而不需被複製到受管理的記憶體中。  

以下是 ExecuteAndSend 方法的語法: 

SqlPipi.ExecuteAndSend (command As SqlCommand) 

從語法可以看出,ExecuteAndSend 方法其實是以一個 SqlCommand物件作為其參數,它會執行 SqlCommand 物件並將結果傳送至用戶端。大家必須瞭解,除了所有實際的執行結果之外,其他的訊息與錯誤也會直接傳送給用戶端。 

程式範例 

以下我們示範如何使用 SqlPipe 物件的 Send 方法將文字串直接傳送至用戶端: 

q  下面這一個 CLR 預存程序存放於類別庫專案 GiveYouString 中,它示範如何使用 SqlPipe 物件的 Send 方法將文字串直接傳送至用戶端:

namespace GiveYouString
{
 public class
GiveYouStringClass
 
{
  [Microsoft.SqlServer.Server.SqlProcedure()]
  public static void GiveYouString()
  {
   //
呼叫 Pipe 物件的 Send 方法將文字串直接傳送給用戶端。
  
SqlContext.Pipe.Send("章立民研究室");
  }
 }
}


請注意,這一個CLR預存程序並沒有任何參數。

q  請執行如下所示之 SQL 指令碼,登錄組件 GiveYouString.dll、建立一個參考所登錄之組件 GiveYouString.dll 的預存程序、然後執行此 CLR 預存程序:

USE 北風貿易;
GO

IF EXISTS (SELECT * FROM sys.procedures WHERE [name] =
'GiveYouString')
DROP PROCEDURE GiveYouString;
GO

IF EXISTS (SELECT * FROM sys.assemblies WHERE [name] =
'GiveYouString')
DROP ASSEMBLY GiveYouString;
GO

--
登錄組件GiveYouString.dll
CREATE ASSEMBLY GiveYouString
FROM 'C:SQL2005DemoCH13GiveYouStringGiveYouStringbinGiveYouString.dll'
WITH permission_set = Safe;
GO

--
建立一個會參考所登錄之組件GiveYouString.dll的預存程序
CREATE PROCEDURE dbo.GiveYouString
AS EXTERNAL NAME GiveYouString.[GiveYouString.GiveYouStringClass].GiveYouString;
GO

EXEC sp_configure 'clr enabled', '1';
GO
RECONFIGURE;
GO

DECLARE @return_value int

--
執行CLR預存程序
EXECUTE @return_value = dbo.GiveYouString;


q  在您執行了上述 SQL 指令後將會發現, 執行CLR 預存程序 GiveYouString 之後並無法取得所傳回的文字串。事實上我們之前就曾經提及,SqlPipe 物件之 Send 方法所傳回的訊息字串會被當作一個資訊訊息傳送給用戶端,至於用戶端要透過哪一種機制來聆聽此訊息,則視用戶端所採用的資料存取應用程式介面(API)而定。如果用戶端使用 ADO.NET,則訊息會透過事件 InfoMessage來傳送。

為了示範如何在前端應用程式中透過 ADO.NET 取得 SqlPipe 物件之 Send 方法所傳回的訊息字串,我們特別設計了一個Windows應用程式 TakeReturnString 來加以實作。從圖表1的執行畫面可以看出,我們果然能夠順利取得 CLR 預存程序使用 SqlPipe 物件之 Send 方法所傳回的文字串。

相關的前端程式碼列示如下:

private void btnRun_Click(object sender, EventArgs e)
{
 //
利用 SqlConnectionStringBuilder 物件來構建連接字串。

 
SqlConnectionStringBuilder connectStringBuilder = new
   SqlConnectionStringBuilder();
 connectStringBuilder.DataSource = @"(local)";
 connectStringBuilder.InitialCatalog = "
北風貿易"
;
 connectStringBuilder.IntegratedSecurity = true;
 
 
try
 
{
  using(SqlConnection northwindConnection = new
    SqlConnection(connectStringBuilder.ConnectionString))
  {
  
northwindConnection.InfoMessage += new
     SqlInfoMessageEventHandler(OnInfoMessage);

  
   northwindConnection.Open();
  
  
SqlCommand cmdLiming = new SqlCommand("dbo.GiveYouString",
     northwindConnection);

  
  
cmdLiming.CommandType = CommandType.StoredProcedure;
   cmdLiming.ExecuteNonQuery();

  }
 }
 catch(Exception ex)
 {
  MessageBox.Show(ex.Message);
 }
}

private static void OnInfoMessage(object sender,
  SqlInfoMessageEventArgs args)
{
 //
顯示 CLR 預存程序利用 SqlPipe.Send 方法所傳回的文字串。
 
MessageBox.Show(args.Message);
}



圖表 1

 


本文節錄並修改自SQL Server 2005 完全實戰
一書

參考書籍:
Visual C# 2005 檔案 IO 與資料存取秘訣

章立民研究室 2007/1/11