SQL Server 2005 から CLR 統合機能として ストアドプロシージャや関数、ユーザー定義型、トリガーを .NET で記述できるようになりました。今回は CLR トリガーを試しに作成してみたのでその覚書を記載します。CRL トリガーについての説明は次のリンクを参照してください。
CLR トリガー
http://msdn.microsoft.com/ja-jp/library/ms131093.aspx
今回作成するCLR トリガーはシンプルな機能で、追加および削除されたレコードの内容を xml で出力ストリームに出力します。Management Studio 上で トリガーが起動すると 追加削除されたレコードがメッセージタブに出力されます。
検証環境は次の通りです
- Visual Studio 2010 Premium, .NET 3.5
- SQL Server 2008 R2
デプロイは Visual Studio のソリューションエクスプローラーから直接行う方法と、手動で T-SQL で行う方法を記載しています。
1. CLR 統合を有効にする
SQL Server で CLR 統合が無効(既定) の場合、有効にしておきます。SQL Server Management Studio を起動して対象のSQL Serverインスタンスに接続し、次のクエリを実行します。
sp_configure 'clr enabled', 1 RECONFIGURE
作成するCLR トリガーがファイルなど外部リソースにアクセスする場合は データベースの TRUSTWORTHY を ON にします。本例では対象のDBを SampleDB としています。
ALTER DATABASE SampleDB SET TRUSTWORTHY ON GO
TRUSTWORTHYはCREATE ASSEMBLY で PERMISSION_SET を UNSET か EXTERNAL_ACCESS にする場合に設定します。(詳細なセキュリティ設定を行えばTRUSTWORTH は OFFのままでも動作させることができるみたいです。)
2. CLRトリガーのプログラムを作成する
Visual Studio を起動し、新規プロジェクトを作成します。今回は下図のように SQL Server プロジェクトテンプレートから Visual C# SQL CLR データベース プロジェクトテンプレートを選択して作成します。下図で ターゲットフレームワークを .NET Framework 3.5 としているので注意してください。本例ではソリューション名を CLRTriggerSample としました。
ソリューションエクスプローラー上で プロジェクトを右クリック→追加→トリガー を選択します。
新しい紅毛の追加画面で、 トリガーを選択します。なめを TestTrigger.cs として追加ボタンをクリックします。
ソースファイルが作成されるので、次のように作成します。トリガー用のスタティックメソッドとして TestTriger を定義しています。その他のメソッド ProcessInsert, ProcessDelete, ProcessOtherAction はトリガー起動の種別に応じてメッセージを作成し、 SqlPipe を使用して出力しています。今回はサンプルのためメッセージを出力していますが通常はメッセージを出力する処理は行わないです。
トリガー用のメソッド TestTrigger には SqlTriggerAttribute が付与されています。本設定は Visual Studio から直接CLRトリガーをデプロイするときに使用される設定です。手動でデプロイする場合はなくても問題はありません。SqlTrigger属性でトリガー名やトリガーを設定するテーブル名、トリガーが起動するイベントを指定できます。
using System; using System.Data; using System.Data.SqlClient; using Microsoft.SqlServer.Server; public partial class Triggers { // SqlTrigger 属性は Visual Studio から直接トリガーを // デプロイする場合に使用する // ターゲットの既存のテーブルまたはビューを入力して、属性行のコメントを解除します // [Microsoft.SqlServer.Server.SqlTrigger (Name="TestTrigger", Target="Table1", Event="FOR UPDATE")] [SqlTrigger(Name="trg_SampleTrigger", Target="TestTable", Event="FOR INSERT, UPDATE, DELETE")] public static void TestTrigger() { // トリガーコンテキスト SqlTriggerContext context = SqlContext.TriggerContext; SqlPipe pipe = SqlContext.Pipe; switch (context.TriggerAction) { case TriggerAction.Insert: ProcessInsert(context, pipe); break; case TriggerAction.Update: ProcessInsert(context, pipe); ProcessDelete(context, pipe); break; case TriggerAction.Delete: ProcessDelete(context, pipe); break; default: ProcessOtherAction(context, pipe); break; } // ユーザーのコードで置き換えてください SqlContext.Pipe.Send("Trigger FIRED"); } private static void ProcessInsert(SqlTriggerContext context, SqlPipe pipe) { using (SqlConnection cn = new SqlConnection("context connection=true")) { cn.Open(); using (SqlCommand cmd = cn.CreateCommand()) { cmd.CommandText = "select * from inserted for xml auto, type"; cmd.CommandType = CommandType.Text; string msg = (string)cmd.ExecuteScalar(); pipe.Send(msg); } } } private static void ProcessDelete(SqlTriggerContext context, SqlPipe pipe) { using (SqlConnection cn = new SqlConnection("context connection=true")) { cn.Open(); using (SqlCommand cmd = cn.CreateCommand()) { cmd.CommandText = "select * from deleted for xml auto, type"; cmd.CommandType = CommandType.Text; string msg = (string)cmd.ExecuteScalar(); pipe.Send(msg); } } } private static void ProcessOtherAction(SqlTriggerContext context, SqlPipe pipe) { pipe.Send(string.Format("Trriger Action {0}", context.TriggerAction.ToString())); } }
ソースをビルドしてエラーが発生しないことを確認してください。
3. Visual Studio からCLRトリガーのデプロイ
Visual Studio からデプロイを行うための設定を行い、実際にデプロイしてみます。
サーバーエクスプローラーを起動(メニューの表示→サーバーエクスプローラーをクリック)し、デプロイ対象のデータベースに接続を行っておいてください。
ソリューションエクスプローラー上で対象のプロジェクトを右クリック→プロパティをクリックします。プロパティ画面が表示されるので、データベースタブを選択します(下図参照)。 接続文字列で参照ボタンをクリックし対象のDBを選択します。アクセス許可のレベルで必要なアクセス許可のレベル(本例ではセーフ) を選択します。ファイルなど外部リソースにアクセスする場合は 外部, ネットワーク上のリソース、Unsafeコードにアクセスする場合はアンセーフなど必要なアクセス許可のレベルの応じて選択します。
本設定は デプロイ時に使用されるCREATE ASSEMBLY ステートメントに影響します
CREATE ASSEMBLY (Transact-SQL)
http://msdn.microsoft.com/ja-jp/library/ms189524.aspx
準備が整いました。
プロジェクトを右クリック→配置 をクリックします。デプロイがが成功すると出力ウィンドウやステータスバーに 配置正常終了 や 配置完了というメッセージが表示されます。
デプロイに使用されるSQLはビルドファイルの出力フォルダに配置されています。中身を確認すると アセンブリ,CLRトリガーのDrop後 アセンブリの登録と CLRトリガーの設定を行っていることがわかります。
デプロイ後動作確認が行えます。その前に 手動でデプロイする手順も記載します。
4. SQL Server Management Studio を使用したT-SQLによる手動デプロイ
T-SQL によるデプロイは簡単です。下記クエリサンプルを SQL Server Management Studio 上で実行します。 アセンブリの登録を行い トリガーの設定を行っています。外部リソースにアクセスしないので、 CREATE ASSEMBLY の Permission_set を SAFE にしています。トリガー作成用のステートメントでは EXTERNAL NAME で CREATE ASSEMBLYで 登録した CLRのアセンブリ名に名前空間、クラス名を含むトリガー用のメソッド名を指定しています。
use SampleDB; GO -- アセンブリとトリガーを削除する場合 -- DROP ASSEMBLY [CLRTriggerSample]; -- DROP TRIGGER trg_SampleTrigger; -- アセンブリ登録 CREATE ASSEMBLY [CLRTriggerSample] FROM 'C:\project\CLRTriggerSample\CLRTriggerSample\bin\Debug\CLRTriggerSample.dll' WITH PERMISSION_SET = SAFE; GO -- トリガー設定 CREATE TRIGGER [dbo].[trg_SampleTrigger] ON [dbo].[TestTable] FOR INSERT, DELETE, UPDATE AS EXTERNAL NAME [CLRTriggerSample].[Triggers].[TestTrigger]; GO
sys.assemblies システムビューを確認すると アセンブリが登録されていることが確認できます。
5. 動作確認
SQL Server Management Studio 上で クエリを作成し トリガーを設定したテーブル(本例では TestTable) に対して INSERT を行うとクエリ結果のメッセージタブに次のようなメッセージが出力されます(テストように作成したテーブルのスキーマによって内容は異なります)。
<inserted id="8" code="1002" value="12" description="Desc2" /> Trigger FIRED
同様にdeleteを行うとメッセージタブに次のようなメッセージが出力されます。
<deleted id="10" code="1003" value="13" description="Desc2" /><deleted id="9" code="1002" value="12" description="Desc2" /> Trigger FIRED
うまく動作しない場合は 冒頭で記載した CLR が有効になっていることを確認してください。CLRトリガーが外部リソースにアクセスする場合はTRUST WORTH がONになっていることを確認してください。
パフォーマンスですが、最初の1回目(初回起動)のトリガーの起動は少し(1秒もないと思いますが) 時間がかかります。それ以降はManagement Studio 上で操作する限りは特に気になりませんでした。CLR統合機能を行った方が効率のよい(もしくはCLR統合機能を使わないと実現できない)場合にしか使用しないと思うのでT-SQLのみのトリガーとパフォーマンスの比較を考えるのはあまり意味がないかもしれませんが。
6. まとめ
今回の説明は以上です。間違い、指摘点などありましたらご連絡ください。
さんのコメント: さんのコメント: