shin'nosuke さんのアレグロモデラート

アレグロモデラート(Allegro moderato)は、速さを示す演奏記号で「穏やかに速く」

Access Web データベースから Oracle のトリガーを呼び出す(基本実装編)

CLR トリガーは以下のようにつくる。

本家のチュートリアルはこちら → CLR トリガー

SharePoint Server または SQL Server が入っているコンピューターで Visual Studio を実行し、SQL Server プロジェクトをつくる。

f:id:lakeside_shinnosuke:20160429220906p:plain

プロジェクトプロパティを開けて、C#VB.NET かを決める。

f:id:lakeside_shinnosuke:20160429221201p:plain

SQL CLR C#VB.NET)というカテゴリーの、SQL CLR C# (VB.NET) Trigger という項目を追加する。

f:id:lakeside_shinnosuke:20160429222744p:plain

生成されたコードに追記したものがこちら。

using System;
using System.Data;
using System.Data.SqlClient;
using Microsoft.SqlServer.Server;

public partial class Triggers{        
    // Enter existing table or view for the target and uncomment the attribute line

    // 以下は適切な名前に変える
    // EventFOR INSERT,UPDATE,DELETE のようにカンマでつなげられる
    [Microsoft.SqlServer.Server.SqlTrigger
    (Name="SqlTrigger1", Target="Table1", Event="INSERT,UPDATE,DELETE")]
    public static void SqlTrigger1 (){
        // Replace with your own code
        // SqlContext.Pipe.SendSQLServer Management Studio(SSMS) の
        // コンソールにメッセージが出力できる
        SqlContext.Pipe.Send("Trigger FIRED");

        SqlCommand command;
        SqlDataReader reader; 
        
        using (SqlConnection connection = new SqlConnection(@"context connection=true")){
            connection.Open();

            switch (SqlContext.TriggerContext.TriggerAction){
                // SqlContext.TriggerContext.TriggerAction で 何が起こったかわかる
                case TriggerAction.Insert:
                    command = new SqlCommand(@"SELECT * FROM INSERTED;",connection);
                    // INSERTEDINSERT された行
                    reader = command.ExecuteReader();
                    break;

                case TriggerAction.Update:
                    command = new SqlCommand(@"SELECT * FROM INSERTED;", connection);
                    // UPDATEINSERTED でとれる
                    reader = command.ExecuteReader();
                    break;

                case TriggerAction.Delete:
                    command = new SqlCommand(@"SELECT * FROM DELETED;", connection);
                    // DELETEDELETED でとる
                    reader = command.ExecuteReader();
                    break;

                default:
                    break;                
            }
        }

    }
}

どうやら、DataSet は使えないようなので、SqlDataReader でがんばること。

これをビルドすると、環境によっては、Visual Studio 上ではビルド失敗となるが、プロジェクトフォルダの obj フォルダに DLL の日付が変わっていれば、ビルドは成功している。これが CLR トリガーのライブラリになる。
(僕は SQLServer の入っているコンピュータで作らなかったので、ビルドには失敗したが、おそらく、SQLServer の入っているコンピュータでビルドすると、自動的にトリガーがデプロイされて、デバッグができるんだと思う。)

できた DLL を SSMS にデプロイするのだが、そのまえに、SSMS から、まず、CLR 統合の有効化のスクリプトを流す。

sp_configure 'clr enabled', 1
RECONFIGURE

つぎに、外部リソースへのアクセスの有効化のスクリプトを流す。

ALTER DATABASE databasename
SET TRUSTWORTHY ON

そして、DLL をデプロイする。トリガーを仕掛けたいデータベースから、プログラミング→アセンブリ→新しいアセンブリをえらぶ。

f:id:lakeside_shinnosuke:20160429225936p:plain

DLL を選択して OK を押す。

f:id:lakeside_shinnosuke:20160429230306p:plain

最後に、実テーブルに対して、トリガーをしかけるために、以下のようなスクリプトを流す。

USE databasename
GO

CREATE TRIGGER [SampleTable_Insert] ON [Access].[SampleTable]
   FOR INSERT
   AS  EXTERNAL NAME [Database1].[Triggers].[SqlTrigger1];
GO

これで CLR トリガーが呼び出せる。

ここまででハマりポイントがひとつある。トリガーを VB.NET でつくったとき、最後に CREATE TRIGGER するところで、

メッセージ 6505、レベル 16、状態 2、プロシージャ SampleTable_Insert、行 2
型 'Triggers' がアセンブリ 'Database1' に見つかりませんでした。

と出る。VB.NET で作ったときは、アセンブリのフルネームは、[Database1].[Database1.Triggers].[SqlTrigger1] となるらしい。デフォルトの名前空間をカブせて指定してください。

さあ、準備は整った。Access Services が作った SQLServer のテーブルに、Oracle のトリガーを呼び出す、CLR トリガーをコーディングしよう!道のりがまだ半分にも満たないことは、このときは知る由もなかった。。。(つづく)