首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 數據庫知識 >  >> SQL Server 資料庫 >> 關於SqlServer

SQL Server CLR 實戰指南(二):CLR 預存程序開發與部署全流程

     編輯:關於SqlServer

CLR 預存程序核心類別與方法

類別/方法用途對應 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執行命令並直接將結果串流回用戶端最高效率的結果回傳方式

七大 CLR 預存程序實作範例

1. 無參無回傳:簡單訊息輸出


[Microsoft.SqlServer.Server.SqlProcedure]
public static void USP_SayHello()
{
    SqlContext.Pipe.Send("USP: Hello from CLR!");
}

2. 有參無回傳:參數透傳


[Microsoft.SqlServer.Server.SqlProcedure]
public static void USP_SayHelloByParameter(SqlString msg)
{
    SqlContext.Pipe.Send(msg.ToString());
}

3. 有參有回傳:純量返回值


[Microsoft.SqlServer.Server.SqlProcedure]
public static SqlInt32 USP_SayHelloByReturn(SqlString msg)
{
    return msg.ToString().Length;  // 返回字串長度
}

4. SqlCommand 執行 DML(傳統方式)


[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();
    }
}

5. ExecuteAndSend 高效執行(推薦)


[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 協議層,大量資料回傳時效能優勢明顯。

6. Send 逐筆傳送多個結果集


[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 產生一個獨立結果集
    }
}

7. SendResults 傳送單一結果集多行(標準模式)


[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 行結果集。應用端處理方式完全不同。

CLR 組件部署 T-SQL 腳本


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 建立
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved