很早就知道能夠用.NET爲SQL Server2005及以上版本編寫存儲過程、觸發器和存儲過程的,不過以前開發的系統要麼由於歷史緣由用的是SQL2000要麼根本用不着在SQL Server中啓用CLR,因此一直沒有嘗試。最近由於項目的緣由,在這方面作了一個調研,如今在這裏分享一下心得。
首先要說明的是要在SQL Server中啓用CLR必須是在SQL Server2005及以上版本,其次在默認狀況下是沒有啓用CLR的,必需要顯示設置爲啓用。好比咱們要在ArticleCollectorDB數據庫中運行用.NET編寫的函數或者存儲過程,至少先要進行下面的SQL語句:html
- exec sp_configure 'clr enabled', 1;--在SQL Server中啓用CLR
- reconfigure;
- go
- --在ArticleCollectorDB數據庫中設置TRUSTWORTHY爲ON
- ALTER DATABASE [ArticleCollectorDB] SET TRUSTWORTHY ON
這時可能會獲得提示要從新啓動SQL Server,若是有此提示則從新啓動一下。
接着咱們在VS中進行編碼,在這裏咱們將分別編寫一個名爲IsMatch的函數和一個名爲SendMail存儲過程。在VS中建立一個名爲NetSkycn.Data的類庫項目,添加一個SqlCLR的類,代碼以下:web
- using System.Data.SqlTypes;
- using System.Net;
- using System.Net.Mail;
- using System.Security.Permissions;
- using System.Text.RegularExpressions;
- using Microsoft.SqlServer.Server;
- namespace NetSkycn.Data
- {
- /// <summary>
- /// 在SQL Server環境中執行的CLR方法,注意提供給SQL Server調用的方法必須有SqlFunction/SqlProcedure Attribute
- /// 做者:周公
- /// 建立日期:2012-05-09
- /// 博客地址:http://blog.csdn.net/zhoufoxcn http://zhoufoxcn.blog.51cto.com
- /// 新浪微博地址:http://weibo.com/zhoufoxcn
- /// </summary>
- public sealed class SqlCLR
- {
- /// <summary>
- /// 判斷字符串是否匹配正則表達式
- /// </summary>
- /// <param name="source">要匹配的文本</param>
- /// <param name="pattern">進行匹配的正則表達式</param>
- /// <param name="options">正則表達式匹配選項,1爲忽略大小寫,2爲多行匹配,3爲忽略大小寫且多行匹配</param>
- /// <returns></returns>
- [SqlFunction(IsDeterministic = true, DataAccess = DataAccessKind.None)]
- public static SqlBoolean IsMatch(string source, string pattern,int options)
- {
- if (string.IsNullOrEmpty(source) || string.IsNullOrEmpty(pattern))
- {
- return SqlBoolean.False;
- }
- RegexOptions regexOptions=RegexOptions.None;
- int optionIgnoreCase = 1;
- int optionMultiline = 2;
- if ((options & optionIgnoreCase) != 0)
- {
- regexOptions = regexOptions | RegexOptions.IgnoreCase;
- }
- if ((options & optionMultiline) != 0)
- {
- regexOptions = regexOptions | RegexOptions.Multiline;
- }
- return (SqlBoolean)(Regex.IsMatch(source, pattern, regexOptions));
- }
- /// <summary>
- /// 發送郵件
- /// </summary>
- /// <param name="to">收件人郵件地址</param>
- /// <param name="from">發件人郵件地址</param>
- /// <param name="subject">郵件主題</param>
- /// <param name="body">郵件內容</param>
- /// <param name="username">登陸smtp主機時用到的用戶名,注意是郵件地址'@'之前的部分</param>
- /// <param name="password">登陸smtp主機時用到的用戶密碼</param>
- /// <param name="smtpHost">發送郵件用到的smtp主機</param>
- [SqlProcedure]
- [SmtpPermission(SecurityAction.Assert)]
- [SecurityPermission(SecurityAction.Assert)]
- public static void SendMail(string to, string from, string subject, string body, string userName, string password, string smtpHost)
- {
- MailAddress addressFrom = new MailAddress(from);
- MailAddress addressTo = new MailAddress(to);
- MailMessage message = new MailMessage(addressFrom, addressTo);
- message.Subject = subject;//設置郵件主題
- message.IsBodyHtml = true;//設置郵件正文爲html格式
- message.Body = body;//設置郵件內容
- SmtpClient client = new SmtpClient(smtpHost);
- //設置發送郵件身份驗證方式
- //注意若是發件人地址是abc@def.com,則用戶名是abc而不是abc@def.com
- client.Credentials = new NetworkCredential(userName, password);
- client.Send(message);
- }
- }
- }
編譯經過以後,記住類庫的物理全路徑,好比:F:\VS2008\netskycn\NetSkycn.Data\bin\Release\NetSkycn.Data.dll,在這裏要強調幾點:1、對於未來提供給SQL Server調用的函數或者存儲過程必須是靜態方法,而且還必須帶有SqlFunction或者SqlProcedure屬性;2、對於一些須要訪問外部網絡資源和安全屬性的還必須添加響應的屬性(如本例中的SendMail方法,若是沒有添加響應的屬性在建立SQL Function/Procedure時會出現錯誤提示)。
如今咱們開始遵循先爲SQL Server建立程序集、後建立函數或者存儲過程的順序來操做,在操做過程當中用到的SQL語句以下:正則表達式
- --在ArticleCollectorDB數據庫中設置TRUSTWORTHY爲ON
- ALTER DATABASE [ArticleCollectorDB] SET TRUSTWORTHY ON
- --若是已經存在該對象則刪除
- IF EXISTS(SELECT * FROM SYS.SYSOBJECTS WHERE NAME='SendMail' AND XTYPE='PC')
- DROP PROCEDURE SendMail
- --若是已經存在該對象則刪除
- IF EXISTS(SELECT * FROM SYS.SYSOBJECTS WHERE NAME='IsMatch' AND XTYPE='FS')
- DROP FUNCTION IsMatch
- --若是已經存在SqlCLR程序集則刪除該程序集
- IF EXISTS(SELECT * FROM SYS.ASSEMBLIES WHERE NAME='SqlCLR')
- DROP ASSEMBLY SqlCLR
- --在SQL Server中建立程序集,,建立的程序集名爲SqlCLR
- CREATE ASSEMBLY SqlCLR FROM 'F:\VS2008\netskycn\NetSkycn.Data\bin\Release\NetSkycn.Data.dll' WITH PERMISSION_SET = UNSAFE
- GO
- --從CLR程序集中建立函數,函數名爲IsMatch,有三個參數,
- --[SqlCLR]是SQL Server中程序集名
- --[NetSkycn.Data.SqlCLR]是.NET中的類的全名(命名空間及類名)
- --[IsMatch]是.NET中類的函數名
- CREATE FUNCTION [dbo].[IsMatch]
- (
- @source AS NVARCHAR(200),
- @pattern AS NVARCHAR(200),
- @option INT=3
- )
- RETURNS BIT
- AS
- EXTERNAL NAME [SqlCLR].[NetSkycn.Data.SqlCLR].[IsMatch];
- GO
- --從CLR程序集中建立函數,函數名爲IsMatch,有三個參數,
- --[SqlCLR]是SQL Server中程序集名
- --[NetSkycn.Data.SqlCLR]是.NET中的類的全名(命名空間及類名)
- --[SendMail]是.NET中類的函數名
- CREATE PROCEDURE [dbo].[SendMail]
- (
- @to AS NVARCHAR(200),
- @from AS NVARCHAR(200),
- @subject AS NVARCHAR(200),
- @body AS NVARCHAR(MAX),
- @userName AS NVARCHAR(200),
- @password AS NVARCHAR(200),
- @smtpHost AS NVARCHAR(200)
- )
- AS
- EXTERNAL NAME [SqlCLR].[NetSkycn.Data.SqlCLR].[SendMail];
- GO
若是沒有獲得任何錯誤提示,則表示建立函數和存儲過程成功。至此咱們會看到以下情形:
sql
這表示建立成功。
測試建立函數的SQL語句(查找article表中title字段是3至5個字段的數據):數據庫
- select * from article where dbo.IsMatch(Title,'^[\u4e00-\u9fa5]{3,5}$',3)=1
測試建立存儲過程的SQL語句:編程
- exec [dbo].SendMail @to='test@qq.com',@from='webmaster@qq.com',@subject='test',@body='This mail was sent by SQL Procedure',@userName='webmaster',@password='123',@smtpHost='smtp.qq.com'
以上代碼在SQL Server 2005中文企業版、SQL Server 2008英文企業版測試經過。
能夠看出在一些SQL語句不夠靈活的狀況下,可使用.NET來編寫存儲過程和函數,經過以上步驟以後和調用SQL語句寫的存儲過程和函數沒有區別,極大地方便了編程。
周公
2012-05-12安全