3

現在、Master データベースの CONTEXT_INFO プロパティを使用して、ログインしたユーザー名を保存し、後でテーブル トリガーで監査用に使用しています。

SQL Azure への移行中に、クロスデータベース接続の問題が発生し、この問題に対する直接的な解決策を見つけることができませんでした。

問題の詳細は次のとおりです。

  1. データ アクセス レイヤーからストアド プロシージャ XXX を呼び出し、ユーザー名をパラメーターとして渡します。
  2. ユーザー名は、XXX の CONTEXT_INFO 値を設定するために使用されます。
  3. CONTEXT_INFO 値は、テーブルの挿入/更新/削除トリガーで使用され、アプリケーション監査用のユーザー名を格納します。

これまでに見つけた解決策:

  1. CONTEXT_INFOとして機能するテーブルをデータベースに作成
  2. データ アクセス レイヤーで 2 つの接続文字列を使用します。1 つはマスター データベース用 (CONTEXT_INFO を設定するため)、もう 1 つはアプリケーション用であり、アプリケーションへの接続を開く前に毎回 SET CONTEXT_INFO を実行します。

しかし、将来的に複数の SQL Azure データベースにデータベースを拡張する場合は特に、どちらのソリューションも危険だと思います。

あなたの支援に感謝。

4

1 に答える 1

4

私がとったアプローチを以下に示します。トリックは、SQL Azure で実行されていないことを確認することでした。その場合、'SET CONTEXT_INFO ...' を呼び出す必要があります。これにより、ローカルの SQL Server Express と Azure で同じコードを変更せずに実行できます。

  1. コンテキスト情報を格納するテーブルを作成します (マスターではなく、同じデータベースに)

    CREATE TABLE [dbo].[ContextInfo] (
        [ContextInfo] varbinary(128) not null,
        [ApplicationUsername] nvarchar(128) not null,
        [UpdatedAt] datetime NOT NULL,
        CONSTRAINT [PK_UserContextInfo] PRIMARY KEY CLUSTERED ([ContextInfo] ASC)
    )
    
  2. アプリケーションから呼び出される「Set Context Info」へのストアド プロシージャを作成します。

    CREATE PROCEDURE [dbo].[SetContextInfo]
      @ApplicationUsername nvarchar(128)
    AS
    
    SET NOCOUNT ON
    
    -- Remove all context items older than an 5 minutes ago
    DELETE
      FROM [dbo].[ContextInfo]
     WHERE [UpdatedAt] < DATEADD(mi, -5, GETUTCDATE())
    
    --
    -- Use the MERGE command to do an update/insert
    -- See: http://technet.microsoft.com/en-us/library/bb510625.aspx
    --
    
    IF SERVERPROPERTY('edition') <> 'SQL Azure'
    BEGIN
        DECLARE @b varbinary(128)
        SET @b = CONVERT(varbinary(128),newid())
        EXEC sp_executesql @statement=N'SET CONTEXT_INFO @b',@params=N'@b varbinary(128)',@b=@b
    END
    
    DECLARE @ContextInfo varbinary(128)
    SELECT @ContextInfo = CONTEXT_INFO()
    
    MERGE [dbo].[ContextInfo] AS target
    USING (SELECT @ContextInfo, @ApplicationUsername) AS source ([ContextInfo], [ApplicationUsername])
       ON (target.[ContextInfo] = source.[ContextInfo])
     WHEN MATCHED THEN 
            UPDATE SET [ApplicationUsername] = source.[ApplicationUsername], [UpdatedAt] = GETUTCDATE()
     WHEN NOT MATCHED THEN  
            INSERT ([ContextInfo], [ApplicationUsername], [UpdatedAt])
            VALUES (source.[ContextInfo], source.[ApplicationUsername], GETUTCDATE());
    
  3. 「コンテキスト情報を取得」するストアド プロシージャを作成する

    CREATE PROCEDURE [dbo].[GetContextInfo]
    AS
        SET NOCOUNT ON
        DECLARE @ContextInfo varbinary(128)
        SELECT @ContextInfo = CONTEXT_INFO()
    
        SELECT [ApplicationUsername]
          FROM [dbo].[ContextInfo]
         WHERE [ContextInfo] = @ContextInfo
    GO
    
  4. トリガー ソースでは、次を使用します。

    DECLARE @UserContext TABLE ([Username] VARCHAR(128))
    INSERT INTO @UserContext (Username)
    EXEC [dbo].[GetContextInfo]
    

これで、ユーザー名がテーブル変数に格納されました。アプリケーションの外部の管理者によって変更が適用された場合は、ユーザー名が設定されていないかどうかを確認し、デフォルトで *SYSTEM_USER* などに設定することもできます。

于 2012-11-01T22:43:28.813 に答える