次の方法で共有


マージ アーティクルのビジネス ロジック ハンドラを実装する方法 (レプリケーション プログラミング)

Microsoft.SqlServer.Replication.BusinessLogicSupport 名前空間は、マージ レプリケーションの同期処理中に発生するイベントを処理する、複雑なビジネス ロジックを記述するためのインターフェイスを実装します。ビジネス ロジック ハンドラのメソッドは、同期中にレプリケートされる変更行ごとに、レプリケーション処理から呼び出すことができます。

ビジネス ロジック ハンドラを実装するための一般的な手順を次に示します。

  1. ビジネス ロジック ハンドラのアセンブリを作成します。
  2. ディストリビュータにアセンブリを登録します。
  3. マージ エージェントが実行されるサーバーにアセンブリを配置します。プル サブスクリプションの場合、エージェントはサブスクライバ上で実行されます。プッシュ サブスクリプションの場合、エージェントはディストリビュータ上で実行されます。Web 同期を使用した場合、エージェントは Web サーバー上で実行されます。
  4. ビジネス ロジック ハンドラを使用するアーティクルを作成するか、またはビジネス ロジック ハンドラを使用する既存のアーティクルを変更します。

指定するビジネス ロジック ハンドラは、同期されるすべての行に対して実行されます。その他のアプリケーションまたはネットワーク サービスに対する複雑なロジックおよび呼び出しは、パフォーマンスに影響を与える可能性があります。ビジネス ロジック ハンドラの詳細については、「マージ同期中のビジネス ロジックの実行」を参照してください。

ビジネス ロジック ハンドラを作成および配置するには

  1. Microsoft Visual Studio で、.NET アセンブリの新しいプロジェクトを作成し、ビジネス ロジック ハンドラの実装コードを記述します。

  2. 次の名前空間の参照をプロジェクトに追加します。

    アセンブリ参照 場所

    Microsoft.SqlServer.Replication.BusinessLogicSupport

    C:\Program Files\Microsoft SQL Server\90\COM (既定のインストール場所)

    System.Data

    GAC (.NET Framework のコンポーネント)

    System.Data.Common

    GAC (.NET Framework のコンポーネント)

  3. BusinessLogicModule クラスをオーバーライドするクラスを追加します。

  4. 処理対象の変更の種類を指定する HandledChangeStates プロパティを実装します。

  5. BusinessLogicModule クラスのメソッドのうち、次のいずれかまたは複数のメソッドをオーバーライドします。

    • CommitHandler - 同期中、データ変更がコミットされたときに呼び出されます。
    • DeleteErrorHandler - DELETE ステートメントをアップロードまたはダウンロードするときにエラーが発生すると呼び出されます。
    • DeleteHandler - DELETE ステートメントをアップロードまたはダウンロードするときに呼び出されます。
    • InsertErrorHandler - INSERT ステートメントをアップロードまたはダウンロードするときにエラーが発生すると呼び出されます。
    • InsertHandler - INSERT ステートメントをアップロードまたはダウンロードするときに呼び出されます。
    • UpdateConflictsHandler - パブリッシャおよびサブスクライバで、UPDATE ステートメントの競合が発生した場合に呼び出されます。
    • UpdateDeleteConflictHandler - パブリッシャおよびサブスクライバで、UPDATE ステートメントと DELETE ステートメントが競合した場合に呼び出されます。
    • UpdateErrorHandler - UPDATE ステートメントをアップロードまたはダウンロードするときにエラーが発生すると呼び出されます。
    • UpdateHandler - UPDATE ステートメントをアップロードまたはダウンロードするときに呼び出されます。
  6. プロジェクトをビルドして、ビジネス ロジック ハンドラ アセンブリを作成します。

  7. アセンブリを、マージ エージェント実行可能ファイル (replmerg.exe) を含むディレクトリ (既定のインストールの場合は C:\Program Files\Microsoft SQL Server\90\COM) に配置するか、.NET グローバル アセンブリ キャッシュ (GAC) にインストールします。マージ エージェント以外のアプリケーションがアセンブリへのアクセスを必要とする場合は、アセンブリを GAC にのみインストールしてください。アセンブリを GAC にインストールするには、.NET Framework SDK のグローバル アセンブリ キャッシュ ツール (Gacutil.exe) を使用します。

    ms147911.note(ja-jp,SQL.90).gifメモ :
    ビジネス ロジック ハンドラは、Web 同期を使用するときに replisapi.dll をホストする IIS サーバーなど、マージ エージェントを実行する各サーバーに配置する必要があります。

ビジネス ロジック ハンドラを登録するには

  1. パブリッシャで、sp_enumcustomresolvers (Transact-SQL) を実行して、アセンブリがまだビジネス ロジック ハンドラとして登録されていないことを確認します。

  2. ディストリビュータで、sp_registercustomresolver (Transact-SQL) を実行します。@article_resolver にビジネス ロジック ハンドラの表示名を、@is_dotnet_assemblytrue を、@dotnet_assembly_name にアセンブリの名前を、@dotnet_class_nameBusinessLogicModule をオーバーライドするクラスの完全修飾名を指定します。

    ms147911.note(ja-jp,SQL.90).gifメモ :
    マージ エージェント実行可能ファイルがあるディレクトリ、マージ エージェントを同期的に起動するアプリケーションがあるディレクトリ、およびグローバル アセンブリ キャッシュ (GAC) の、いずれとも異なる場所にビジネス ロジック ハンドラ アセンブリが配置されている場合は、@dotnet_assembly_name にアセンブリ名を含む完全なパスを指定する必要があります。Web 同期を使用する場合は、Web サーバーでアセンブリの位置を指定する必要があります。

新しいテーブル アーティクルでビジネス ロジック ハンドラを使用するには

  1. @article_resolver にビジネス ロジック ハンドラの表示名を指定して、アーティクルを定義する sp_addmergearticle (Transact-SQL) を実行します。詳細については、「アーティクルを定義する方法 (レプリケーション Transact-SQL プログラミング)」を参照してください。

既存のテーブル アーティクルでビジネス ロジック ハンドラを使用するには

  1. @publication@article を指定し、@propertyarticle_resolver を、@value にビジネス ロジック ハンドラの表示名を指定して、sp_changemergearticle (Transact-SQL) を実行します。

使用例

次の例に、監査ログを作成するビジネス ロジック ハンドラを示します。

using System;
using System.Text;
using System.Data;
using System.Data.Common;
using Microsoft.SqlServer.Replication.BusinessLogicSupport;
using Microsoft.Samples.SqlServer.BusinessLogicHandler;

namespace Microsoft.Samples.SqlServer.BusinessLogicHandler
{
    public class OrderEntryBusinessLogicHandler :
      Microsoft.SqlServer.Replication.BusinessLogicSupport.BusinessLogicModule
    {
        // Variables to hold server names.
        private string publisherName;
        private string subscriberName;

        public OrderEntryBusinessLogicHandler()
        {
        }

        // Implement the Initialize method to get publication 
        // and subscription information.
        public override void Initialize(
            string publisher,
            string subscriber,
            string distributor,
            string publisherDB,
            string subscriberDB,
            string articleName)
        {
            // Set the Publisher and Subscriber names.
            publisherName = publisher;
            subscriberName = subscriber;
        }

        // Declare what types of row changes, conflicts, or errors to handle.
        override public ChangeStates HandledChangeStates
        {
            get
            {
                // Handle Subscriber inserts, updates and deletes.
                return ChangeStates.SubscriberInserts |
                  ChangeStates.SubscriberUpdates | ChangeStates.SubscriberDeletes;
            }
        }

        public override ActionOnDataChange InsertHandler(SourceIdentifier insertSource,
          DataSet insertedDataSet, ref DataSet customDataSet, ref int historyLogLevel,
          ref string historyLogMessage)
        {
            if (insertSource == SourceIdentifier.SourceIsSubscriber)
            {
                // Build a line item in the audit message to log the Subscriber insert.
                StringBuilder AuditMessage = new StringBuilder();
                AuditMessage.Append(String.Format("A new order was entered at {0}. " +
                  "The SalesOrderID for the order is :", subscriberName));
                AuditMessage.Append(insertedDataSet.Tables[0].Rows[0]["SalesOrderID"].ToString());
                AuditMessage.Append("The order must be shipped by :");
                AuditMessage.Append(insertedDataSet.Tables[0].Rows[0]["DueDate"].ToString());

                // Set the reference parameter to write the line to the log file.
                historyLogMessage = AuditMessage.ToString();
                
                // Set the history log level to the default verbose level.
                historyLogLevel = 1;

                // Accept the inserted data in the Subscriber's data set and 
                // apply it to the Publisher.
                return ActionOnDataChange.AcceptData;
            }
            else
            {
                return base.InsertHandler(insertSource, insertedDataSet, ref customDataSet,
                  ref historyLogLevel, ref historyLogMessage);
            }
        }

        public override ActionOnDataChange UpdateHandler(SourceIdentifier updateSource,
          DataSet updatedDataSet, ref DataSet customDataSet, ref int historyLogLevel,
          ref string historyLogMessage)
        {
            if (updateSource == SourceIdentifier.SourceIsPublisher)
            {
                // Build a line item in the audit message to log the Subscriber update.
                StringBuilder AuditMessage = new StringBuilder();
                AuditMessage.Append(String.Format("An existing order was updated at {0}. " +
                  "The SalesOrderID for the order is ", subscriberName));
                AuditMessage.Append(updatedDataSet.Tables[0].Rows[0]["SalesOrderID"].ToString());
                AuditMessage.Append("The order must now be shipped by :");
                AuditMessage.Append(updatedDataSet.Tables[0].Rows[0]["DueDate"].ToString());

                // Set the reference parameter to write the line to the log file.
                historyLogMessage = AuditMessage.ToString();
                // Set the history log level to the default verbose level.
                historyLogLevel = 1;

                // Accept the updated data in the Subscriber's data set and apply it to the Publisher.
                return ActionOnDataChange.AcceptData;
            }
            else
            {
                return base.UpdateHandler(updateSource, updatedDataSet,
                  ref customDataSet, ref historyLogLevel, ref historyLogMessage);
            }
        }

        public override ActionOnDataDelete DeleteHandler(SourceIdentifier deleteSource,
          DataSet deletedDataSet, ref int historyLogLevel, ref string historyLogMessage)
        {
            if (deleteSource == SourceIdentifier.SourceIsSubscriber)
            {
                // Build a line item in the audit message to log the Subscriber deletes.
                // Note that the rowguid is the only information that is 
                // available in the dataset.
                StringBuilder AuditMessage = new StringBuilder();
                AuditMessage.Append(String.Format("An existing order was deleted at {0}. " +
                  "The rowguid for the order is ", subscriberName));
                AuditMessage.Append(deletedDataSet.Tables[0].Rows[0]["rowguid"].ToString());

                // Set the reference parameter to write the line to the log file.
                historyLogMessage = AuditMessage.ToString();
                // Set the history log level to the default verbose level.
                historyLogLevel = 1;

                // Accept the delete and apply it to the Publisher.
                return ActionOnDataDelete.AcceptDelete;
            }
            else
            {
                return base.DeleteHandler(deleteSource, deletedDataSet,
                  ref historyLogLevel, ref historyLogMessage);
            }
        }
    }
}
Imports System
Imports System.Text
Imports System.Data
Imports System.Data.Common
Imports Microsoft.SqlServer.Replication.BusinessLogicSupport

Namespace Microsoft.Samples.SqlServer.BusinessLogicHandler
    Public Class OrderEntryBusinessLogicHandler
        Inherits BusinessLogicModule

        ' Variables to hold server names.
        Private publisherName As String
        Private subscriberName As String

        ' Implement the Initialize method to get publication 
        ' and subscription information.
        Public Overrides Sub Initialize( _
        ByVal publisher As String, _
        ByVal subscriber As String, _
        ByVal distributor As String, _
        ByVal publisherDB As String, _
        ByVal subscriberDB As String, _
        ByVal articleName As String _
      )
            ' Set the Publisher and Subscriber names.
            publisherName = publisher
            subscriberName = subscriber
        End Sub

        ' Declare what types of row changes, conflicts, or errors to handle.
        Public Overrides ReadOnly Property HandledChangeStates() As ChangeStates
            Get
                ' Handle Subscriber inserts, updates and deletes.
                Return (ChangeStates.SubscriberInserts Or _
                 ChangeStates.SubscriberUpdates Or ChangeStates.SubscriberDeletes)
            End Get
        End Property

        Public Overrides Function InsertHandler(ByVal insertSource As SourceIdentifier, _
        ByVal insertedDataSet As DataSet, ByRef customDataSet As DataSet, _
        ByRef historyLogLevel As Integer, ByRef historyLogMessage As String) _
        As ActionOnDataChange

            If insertSource = SourceIdentifier.SourceIsSubscriber Then
                ' Build a line item in the audit message to log the Subscriber insert.
                Dim AuditMessage As StringBuilder = New StringBuilder()
                AuditMessage.Append(String.Format("A new order was entered at {0}. " + _
                 "The SalesOrderID for the order is :", subscriberName))
                AuditMessage.Append(insertedDataSet.Tables(0).Rows(0)("SalesOrderID").ToString())
                AuditMessage.Append("The order must be shipped by :")
                AuditMessage.Append(insertedDataSet.Tables(0).Rows(0)("DueDate").ToString())

                ' Set the reference parameter to write the line to the log file.
                historyLogMessage = AuditMessage.ToString()

                ' Set the history log level to the default verbose level.
                historyLogLevel = 1

                ' Accept the inserted data in the Subscriber's data set and 
                ' apply it to the Publisher.
                Return ActionOnDataChange.AcceptData
            Else
                Return MyBase.InsertHandler(insertSource, insertedDataSet, customDataSet, _
                 historyLogLevel, historyLogMessage)
            End If
        End Function
        Public Overrides Function UpdateHandler(ByVal updateSource As SourceIdentifier, _
        ByVal updatedDataSet As DataSet, ByRef customDataSet As DataSet, _
        ByRef historyLogLevel As Integer, ByRef historyLogMessage As String) _
        As ActionOnDataChange

            If updateSource = SourceIdentifier.SourceIsPublisher Then
                ' Build a line item in the audit message to log the Subscriber update.
                Dim AuditMessage As StringBuilder = New StringBuilder()
                AuditMessage.Append(String.Format("An existing order was updated at {0}. " + _
                 "The SalesOrderID for the order is ", subscriberName))
                AuditMessage.Append(updatedDataSet.Tables(0).Rows(0)("SalesOrderID").ToString())
                AuditMessage.Append("The order must now be shipped by :")
                AuditMessage.Append(updatedDataSet.Tables(0).Rows(0)("DueDate").ToString())

                ' Set the reference parameter to write the line to the log file.
                historyLogMessage = AuditMessage.ToString()
                ' Set the history log level to the default verbose level.
                historyLogLevel = 1

                ' Accept the updated data in the Subscriber's data set and apply it to the Publisher.
                Return ActionOnDataChange.AcceptData
            Else
                Return MyBase.UpdateHandler(updateSource, updatedDataSet, _
                 customDataSet, historyLogLevel, historyLogMessage)
            End If
        End Function
        Public Overrides Function DeleteHandler(ByVal deleteSource As SourceIdentifier, _
        ByVal deletedDataSet As DataSet, ByRef historyLogLevel As Integer, _
         ByRef historyLogMessage As String) As ActionOnDataDelete
            If deleteSource = SourceIdentifier.SourceIsSubscriber Then
                ' Build a line item in the audit message to log the Subscriber deletes.
                ' Note that the rowguid is the only information that is 
                ' available in the dataset.
                Dim AuditMessage As StringBuilder = New StringBuilder()
                AuditMessage.Append(String.Format("An existing order was deleted at {0}. " + _
                 "The rowguid for the order is ", subscriberName))
                AuditMessage.Append(deletedDataSet.Tables(0).Rows(0)("rowguid").ToString())

                ' Set the reference parameter to write the line to the log file.
                historyLogMessage = AuditMessage.ToString()
                ' Set the history log level to the default verbose level.
                historyLogLevel = 1

                ' Accept the delete and apply it to the Publisher.
                Return ActionOnDataDelete.AcceptDelete
            Else
                Return MyBase.DeleteHandler(deleteSource, deletedDataSet, _
                 historyLogLevel, historyLogMessage)
            End If
        End Function
    End Class
End Namespace

次の例では、ビジネス ロジック ハンドラ アセンブリをディストリビュータに登録し、カスタム ビジネス ロジックを使用するように既存のマージ アーティクルを変更します。

DECLARE @publication AS sysname;
DECLARE @article AS sysname;
DECLARE @friendlyname AS sysname;
DECLARE @assembly AS nvarchar(500);
DECLARE @class AS sysname;
SET @publication = N'AdvWorksCustomers';
SET @article = N'Customers';
SET @friendlyname = N'OrderEntryLogic';
SET @assembly = N'C:\Program Files\Microsoft SQL Server\90\COM\CustomLogic.dll';
SET @class = N'Microsoft.Samples.SqlServer.BusinessLogicHandler.OrderEntryBusinessLogicHandler';

-- Register the business logic handler at the Distributor.
EXEC sys.sp_registercustomresolver 
    @article_resolver = @friendlyname,
    @resolver_clsid = NULL,
    @is_dotnet_assembly = N'true',
    @dotnet_assembly_name = @assembly,
    @dotnet_class_name = @class;

-- Add an article that uses the business logic handler
-- at the Publisher.
EXEC sp_changemergearticle 
    @publication = @publication, 
    @article = @article,
    @property = N'article_resolver', 
    @value = @friendlyname,
    @force_invalidate_snapshot = 0,
    @force_reinit_subscription = 0;
GO

参照

処理手順

ビジネス ロジック ハンドラをデバッグする方法 (レプリケーション プログラミング)
マージ アーティクル用の COM ベース カスタム競合回避モジュールを実装する方法 (レプリケーションのプログラミング)
マージ アーティクルに対してストアド プロシージャ ベースのカスタム競合回避モジュールを実装する方法 (レプリケーション Transact-SQL プログラミング)

ヘルプおよび情報

SQL Server 2005 の参考資料の入手