| 類別/方法 | 用途 | 對應 ADO.NET 概念 |
|---|---|---|
SqlDataRecord | 單筆資料記錄容器 | 類似 DataRow |
SqlMetaData | 欄位定義(名稱、型別、長度) | 類似 DataColumn |
SqlContext.Pipe.SendResultsStart | 開始傳送結果集(需先定義結構描述) | 開啟結果集串流 |
SqlContext.Pipe.SendResultsRow | 傳送單筆資料列 | Rows.Add() |
SqlContext.Pipe.SendResultsEnd | 結束結果集傳送 | 關閉串流 |
SqlContext.Pipe.Send | 直接傳送訊息/記錄/結果集給用戶端 | Console.Write/回傳結果 |
SqlContext.Pipe.ExecuteAndSend | 執行命令並直接將結果串流回用戶端 | 最高效率的結果回傳方式 |
[Microsoft.SqlServer.Server.SqlProcedure]
public static void USP_SayHello()
{
SqlContext.Pipe.Send("USP: Hello from CLR!");
}
[Microsoft.SqlServer.Server.SqlProcedure]
public static void USP_SayHelloByParameter(SqlString msg)
{
SqlContext.Pipe.Send(msg.ToString());
}
[Microsoft.SqlServer.Server.SqlProcedure]
public static SqlInt32 USP_SayHelloByReturn(SqlString msg)
{
return msg.ToString().Length; // 返回字串長度
}
[Microsoft.SqlServer.Server.SqlProcedure]
public static void USP_ExecuteBySqlCommand(SqlString stor_id, SqlString stor_name)
{
using (SqlConnection con = new SqlConnection("context connection=true"))
{
con.Open();
SqlCommand com = new SqlCommand(
string.Format("INSERT INTO stores VALUES('{0}','{1}')", stor_id, stor_name), con);
com.ExecuteNonQuery();
}
}
[Microsoft.SqlServer.Server.SqlProcedure]
public static void USP_ExecuteByExecuteAndSend(SqlString stor_id, SqlString stor_name)
{
using (SqlConnection con = new SqlConnection("context connection=true"))
{
con.Open();
SqlCommand com = new SqlCommand(
string.Format("INSERT INTO stores VALUES('{0}','{1}')", stor_id, stor_name), con);
SqlContext.Pipe.ExecuteAndSend(com); // 結果直接串流回用戶端,不經托管記憶體
}
}
效能差異:
ExecuteAndSend避免資料複製到 .NET 記憶體再封包,直接由 SQLOS 串流至 TDS 協議層,大量資料回傳時效能優勢明顯。
[Microsoft.SqlServer.Server.SqlProcedure]
public static void UPS_PipeSendSqlDataRecord()
{
SqlDataRecord record = new SqlDataRecord(new SqlMetaData[] {
new SqlMetaData("Col1", SqlDbType.NVarChar, 100),
new SqlMetaData("Col2", SqlDbType.Int)
});
for (int i = 1; i < 5; i++)
{
record.SetString(0, i.ToString());
record.SetInt32(1, i);
SqlContext.Pipe.Send(record); // 每次 Send 產生一個獨立結果集
}
}
[Microsoft.SqlServer.Server.SqlProcedure]
public static void UPS_PipeSendResultSqlDataRecord()
{
SqlDataRecord record = new SqlDataRecord(new SqlMetaData[] {
new SqlMetaData("Col1", SqlDbType.NVarChar, 100),
new SqlMetaData("Col2", SqlDbType.Int)
});
SqlContext.Pipe.SendResultsStart(record); // 定義結構描述
for (int i = 0; i < 5; i++)
{
record.SetString(0, i.ToString());
record.SetInt32(1, i);
SqlContext.Pipe.SendResultsRow(record); // 填充資料列
}
SqlContext.Pipe.SendResultsEnd(); // 結束並回傳單一結果集
}
差異:範例 6 回傳 5 個單行結果集;範例 7 回傳 1 個 5 行結果集。應用端處理方式完全不同。
USE pubs;
GO
-- 1. 建立組件(假設 DLL 位於 C:\CLRDemo.dll)
CREATE ASSEMBLY CLRDemoAssembly
FROM 'C:\CLRDemo.dll'
WITH PERMISSION_SET = SAFE; -- 或 EXTERNAL_ACCESS/UNSAFE 視權限需求
GO
-- 2. 建立預存程序對應進入點
-- 格式:EXTERNAL NAME AssemblyName.[Namespace.]ClassName.MethodName
CREATE PROC USP_SayHello
AS EXTERNAL NAME CLRDemoAssembly.StoredProcedures.USP_SayHello;
GO
CREATE PROC USP_SayHelloByParameter (@Msg NVARCHAR(128))
AS EXTERNAL NAME CLRDemoAssembly.StoredProcedures.USP_SayHelloByParameter;
GO
CREATE PROC USP_SayHelloByReturn (@Msg NVARCHAR(128))
AS EXTERNAL NAME CLRDemoAssembly.StoredProcedures.USP_SayHelloByReturn;
GO
CREATE PROC USP_ExecuteBySqlCommand (@Id NVARCHAR(4), @Name NVARCHAR(32))
AS EXTERNAL NAME CLRDemoAssembly.StoredProcedures.USP_ExecuteBySqlCommand;
GO
CREATE PROC USP_ExecuteByExecuteAndSend (@Id NVARCHAR(4), @Name NVARCHAR(32))
AS EXTERNAL NAME CLRDemoAssembly.StoredProcedures.USP_ExecuteByExecuteAndSend;
GO
CREATE PROC UPS_PipeSendSqlDataRecord
AS EXTERNAL NAME CLRDemoAssembly.StoredProcedures.UPS_PipeSendSqlDataRecord;
GO
CREATE PROC UPS_PipeSendResultSqlDataRecord
AS EXTERNAL NAME CLRDemoAssembly.StoredProcedures.UPS_PipeSendResultSqlDataRecord;
GO
-- 呼叫
EXEC USP_SayHello;
EXEC USP_SayHelloByParameter 'Hello CLR';
DECLARE @Len INT; EXEC @Len = USP_SayHelloByReturn 'Test'; SELECT @Len;
-- 移除(順序:先程序後組件)
DROP PROC USP_SayHello;
DROP PROC USP_SayHelloByParameter;
DROP PROC USP_SayHelloByReturn;
DROP PROC USP_ExecuteBySqlCommand;
DROP PROC USP_ExecuteByExecuteAndSend;
DROP PROC UPS_PipeSendSqlDataRecord;
DROP PROC UPS_PipeSendResultSqlDataRecord;
GO
DROP ASSEMBLY CLRDemoAssembly;
GO
若 C# 程式碼有命名空間(如 namespace MyCLR { class StoredProcedures { ... } }):
CREATE PROC USP_SayHello
AS EXTERNAL NAME CLRDemoAssembly.[MyCLR.StoredProcedures].USP_SayHello;
-- 類別全名需用方括號包裹
| PERMISSION_SET | 允許操作 | 適用場景 |
|---|---|---|
| SAFE(預設) | 純運算、記憶體存取、內部資料存取 | 大多數 CLR 預存程序/函數 |
| EXTERNAL_ACCESS | 檔案系統、網路、登錄、環境變數 | 需讀寫外部資源 |
| UNSAFE | 非受控程式碼、P/Invoke、靜態變數共享 | 極少數極複雜場景,需 sysadmin 建立 |