Sdílet prostřednictvím


Implementace obslužné rutiny obchodní logiky pro článek sloučení

platí pro:SQL Server

Toto téma popisuje, jak implementovat obslužnou rutinu obchodní logiky pro článek sloučení v SQL Serveru pomocí programování replikace nebo objektů RMO (Replication Management Objects).

Jmenný prostor Microsoft.SqlServer.Replication.BusinessLogicSupport implementuje rozhraní, které vám umožňuje psát složitou obchodní logiku pro zpracování událostí, ke kterým dochází během procesu synchronizace při sloučení replikací. Metody v obslužné rutině obchodní logiky lze vyvolat procesem replikace pro každý změněný řádek, který se replikuje během synchronizace.

Proces implementace obslužné rutiny obchodní logiky je obecně:

  1. Vytvořte sestavení zpracování obchodní logiky.

  2. Zaregistrujte montáž u distributora.

  3. Nasaďte sestavení na server, na kterém běží agent sloučení. V případě předplatného typu pull agent běží na odběrateli, a pro předplatné typu push agent běží na distributoru. Když používáte synchronizaci webu, agent běží na webovém serveru.

  4. Vytvořte článek, který používá obslužnou rutinu obchodní logiky nebo upraví existující článek tak, aby používal obslužnou rutinu obchodní logiky.

Zadaná obslužná rutina obchodní logiky se spustí pro každý synchronizovaný řádek. Komplexní logika a volání jiných aplikací nebo síťových služeb můžou mít vliv na výkon. Další informace o zpracovačích obchodní logiky naleznete v tématu Provádění obchodní logiky při synchronizaci sloučení.

V tomto tématu

Použití programování replikace

Vytvořit a nasadit obslužný program obchodní logiky

  1. V sadě Microsoft Visual Studio vytvořte nový projekt pro sestavení .NET obsahující kód, který implementuje zpracovatele obchodní logiky.

  2. Přidejte odkazy na projekt pro následující obory názvů.

    Referenční sestavení Umístění
    Microsoft.SqlServer.Replication.BusinessLogicSupport C:\Program Files\Microsoft SQL Server\nnn\COM (výchozí instalace)
    System.Data GAC (součást rozhraní .NET Framework)
    System.Data.Common GAC (součást rozhraní .NET Framework)
  3. Přidejte třídu, která nahradí třídu BusinessLogicModule.

  4. Implementujte HandledChangeStates vlastnost označující typy změn, které se zpracovávají.

  5. Přepište jednu nebo více z následujících metod třídy BusinessLogicModule:

    • CommitHandler – vyvolá se při potvrzení změny dat během synchronizace.

    • DeleteErrorHandler – vyvolá se, když dojde k chybě při nahrání nebo stažení příkazu DELETE.

    • DeleteHandler – vyvolá se při nahrávání nebo stahování příkazů DELETE.

    • InsertErrorHandler – vyvolá se, když dojde k chybě při nahrání nebo stažení příkazu INSERT.

    • InsertHandler – vyvolá se při nahrávání nebo stahování příkazů INSERT.

    • UpdateConflictsHandler – vyvolán, když dojde ke konfliktním příkazům UPDATE na straně vydavatele a odběratele.

    • UpdateDeleteConflictHandler – vyvoláno, když příkazy UPDATE kolidují s příkazy DELETE v Publisheru a Odběrateli.

    • UpdateErrorHandler – vyvolá se, když dojde k chybě při nahrání nebo stažení příkazu UPDATE.

    • UpdateHandler – vyvolá se při nahrávání nebo stahování příkazů UPDATE.

  6. Sestavte projekt k vytvoření sestavení pro obsluhu obchodní logiky.

  7. Nasaďte sestavení v adresáři, který obsahuje spustitelný soubor agenta sloučení (replmerg.exe), který pro výchozí instalaci je C:\Program Files\Microsoft SQL Server\nnn\COM nebo jej nainstalujte do globální mezipaměti sestavení .NET (GAC). Sestavení byste měli nainstalovat pouze v GAC, pokud aplikace jiné než slučovací agent vyžadují přístup k sestavení. Sestavení lze nainstalovat do GAC pomocí nástroje globální mezipaměti sestavení (Gacutil.exe), který je součástí sady .NET Framework SDK.

    Poznámka

    Obslužná rutina obchodní logiky musí být nasazena na každém serveru, na kterém běží agent sloučení, který zahrnuje server služby IIS, který je hostitelem replisapi.dll při použití webové synchronizace.

Registrace obslužné rutiny obchodní logiky

  1. Na Publisheru spusťte sp_enumcustomresolvers (Transact-SQL) a ověřte, že sestavení ještě není zaregistrované jako obslužná rutina obchodní logiky.

  2. U distributora spusťte sp_registercustomresolver (Transact-SQL), zadejte popisný název obslužné rutiny obchodní logiky pro @article_resolver, hodnotu true pro @is_dotnet_assembly, název sestavení pro @dotnet_assembly_namea plně kvalifikovaný název třídy, která přepisuje BusinessLogicModule pro @dotnet_class_name.

    Poznámka

    Pokud sestavení není nasazeno ve stejném adresáři jako spustitelný soubor slučovacího agenta, ve stejném adresáři jako aplikace, která synchronně spouští slučovacího agenta, nebo v globální mezipaměti sestavení (GAC), musíte zadat úplnou cestu s názvem sestavení pro @dotnet_assembly_name. Při použití synchronizace webu je nutné zadat umístění sestavení na webovém serveru.

Použití obslužné rutiny obchodní logiky s novou položkou tabulky

  1. Spusťte sp_addmergearticle (Transact-SQL), abyste definovali článek a zadali popisný název pro obslužnou rutinu obchodní logiky pro článek @article_resolver. Další informace naleznete v tématu Definování článku.

Použití obslužné rutiny obchodní logiky s existující položkou tabulky

  1. Spusťte sp_changemergearticle (Transact-SQL), zadejte @publication, @article, hodnotu article_resolver pro @propertya přívětivý název obslužné rutiny obchodní logiky pro @value.

Příklady (programování replikace)

Tento příklad ukazuje obslužnou rutinu obchodní logiky, která vytvoří protokol auditu.

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

Následující příklad zaregistruje sestavení obslužné rutiny obchodní logiky u distribučního serveru a změní existující slučovací položku tak, aby používala tuto vlastní obchodní logiku.

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\120\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

Použití objektů správy replikace (RMO)

Vytvoření zpracovatele obchodní logiky

  1. V sadě Microsoft Visual Studio vytvořte nový projekt sestavení .NET obsahující kód, který implementuje zpracovač obchodní logiky.

  2. Přidejte odkazy na projekt pro následující obory názvů.

    Referenční sestavení Umístění
    Microsoft.SqlServer.Replication.BusinessLogicSupport C:\Program Files\Microsoft SQL Server\nnn\COM (výchozí instalace)
    System.Data GAC (součást rozhraní .NET Framework)
    System.Data.Common GAC (součást rozhraní .NET Framework)
  3. Přidejte třídu, která přepíše třídu BusinessLogicModule.

  4. Implementujte HandledChangeStates vlastnost označující typy změn, které se zpracovávají.

  5. Přepište jednu nebo více z následujících metod třídy BusinessLogicModule:

    • CommitHandler – vyvolá se při potvrzení změny dat během synchronizace.

    • DeleteErrorHandler – vyvolá se, pokud dojde k chybě při nahrání nebo stažení příkazu DELETE.

    • DeleteHandler – vyvolá se při nahrávání nebo stahování příkazů DELETE.

    • InsertErrorHandler – vyvolá se, pokud dojde k chybě při nahrání nebo stažení příkazu INSERT.

    • InsertHandler – vyvolá se při nahrávání nebo stahování příkazů INSERT.

    • UpdateConflictsHandler – vyvoláno, když dojde ke konfliktním příkazům UPDATE na straně vydavatele a odběratele.

    • UpdateDeleteConflictHandler – vyvoláno, když příkazy UPDATE kolidují s příkazy DELETE v Publisheru a Odběrateli.

    • UpdateErrorHandler – vyvolá se, pokud dojde k chybě při nahrání nebo stažení příkazu UPDATE.

    • UpdateHandler – vyvolá se při nahrávání nebo stahování příkazů UPDATE.

    Poznámka

    Všechny konflikty článků, které nejsou explicitně zpracovány vaší vlastní obchodní logikou, řeší výchozí řešitel těchto článků.

  6. Zkompilujte projekt pro vytvoření sestavení obchodní logiky.

Jak zaregistrovat obslužnou rutinu obchodní logiky

  1. Vytvořte připojení k distributoru pomocí třídy ServerConnection.

  2. Vytvořte instanci třídy ReplicationServer. Předejte ServerConnection z kroku 1.

  3. Zavolejte EnumBusinessLogicHandlers a zkontrolujte vrácený objekt ArrayList a ujistěte se, že sestavení ještě nebylo registrováno jako obslužná rutina obchodní logiky.

  4. Vytvořte instanci třídy BusinessLogicHandler. Zadejte následující vlastnosti:

    • DotNetAssemblyName – název sestavení .NET. Pokud sestavení není nasazeno ve stejném adresáři jako spustitelný soubor slučovacího agenta, ve stejném adresáři jako aplikace, která synchronně spustí slučovacího agenta, nebo v GAC, musíte zahrnout úplnou cestu s názvem sestavení. Při použití obslužné rutiny obchodní logiky s webovou synchronizací musíte zahrnout úplnou cestu s názvem sestavení.

    • DotNetClassName – plně kvalifikovaný název třídy, která přepíše BusinessLogicModule a implementuje obslužnou rutinu obchodní logiky.

    • FriendlyName – přátelský název, který použijete při používání obslužné rutiny obchodní logiky.

    • IsDotNetAssembly – hodnota true.

Nasazení obslužné rutiny obchodní logiky

  1. Nasaďte sestavení na server, kde agent sloučení běží v umístění souboru určeném při registraci obslužné rutiny obchodní logiky u distributora. V případě předplatného vyžádané replikace běží agent na odběrateli a pro nabízené předplatné běží agent na distributoru. Když používáte synchronizaci webu, agent běží na webovém serveru. Pokud nebyla úplná cesta zahrnuta s názvem sestavení při registraci obslužné rutiny obchodní logiky, nasaďte sestavení ve stejném adresáři jako spustitelný soubor Merge Agent ve stejném adresáři jako aplikace, která synchronně spustí agenta sloučení. Sestavení můžete nainstalovat do GAC, pokud existuje více aplikací, které používají stejné sestavení.

Použití obslužné rutiny obchodní logiky s novou položkou tabulky

  1. Vytvořte připojení k Publisheru pomocí třídy ServerConnection.

  2. Vytvořte instanci třídy MergeArticle. Nastavte následující vlastnosti:

  3. Volejte metodu Create. Další informace naleznete v tématu Definování článku.

Použití zpracovatele obchodní logiky s existujícím záznamem tabulky

  1. Vytvořte připojení k Publisheru pomocí třídy ServerConnection.

  2. Vytvořte instanci třídy MergeArticle.

  3. Nastavte vlastnosti Name, PublicationNamea DatabaseName.

  4. Nastavte připojení z kroku 1 pro vlastnost ConnectionContext.

  5. Zavolejte metodu LoadProperties, abyste získali vlastnosti objektu. Pokud tato metoda vrátí false, buď vlastnosti článku v kroku 3 byly definovány nesprávně nebo neexistuje článek. Další informace naleznete v tématu Zobrazit a upravit vlastnosti článku.

  6. Nastavte přátelský název obslužné rutiny obchodní logiky pro ArticleResolver. Toto je hodnota vlastnosti FriendlyName zadaná při registraci obslužné rutiny obchodní logiky.

Příklady (RMO)

Tento příklad je obslužná rutina obchodní logiky, která protokoluje informace o vkládání, aktualizacích a odstraňování u odběratele.

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

Tento příklad zaregistruje obslužnou rutinu obchodní logiky u Distributora.

// Specify the Distributor name and business logic properties.
string distributorName = publisherInstance;
string assemblyName = @"C:\Program Files\Microsoft SQL Server\110\COM\CustomLogic.dll";
string className = "Microsoft.Samples.SqlServer.BusinessLogicHandler.OrderEntryBusinessLogicHandler";
string friendlyName = "OrderEntryLogic";

ReplicationServer distributor;
BusinessLogicHandler customLogic;

    // Create a connection to the Distributor.
ServerConnection distributorConn = new ServerConnection(distributorName);

try
{
    // Connect to the Distributor.
    distributorConn.Connect();

    // Set the Distributor properties.
    distributor = new ReplicationServer(distributorConn);

    // Set the business logic handler properties.
    customLogic = new BusinessLogicHandler();
    customLogic.DotNetAssemblyName = assemblyName;
    customLogic.DotNetClassName = className;
    customLogic.FriendlyName = friendlyName;
    customLogic.IsDotNetAssembly = true;

    Boolean isRegistered = false;

    // Check if the business logic handler is already registered at the Distributor.
    foreach (BusinessLogicHandler registeredLogic
        in distributor.EnumBusinessLogicHandlers())
    {
        if (registeredLogic == customLogic)
        {
            isRegistered = true;
        }
    }

    // Register the custom logic.
    if (!isRegistered)
    {
        distributor.RegisterBusinessLogicHandler(customLogic);
    }
}
catch (Exception ex)
{
    // Do error handling here.
    throw new ApplicationException(string.Format(
        "The {0} assembly could not be registered.",
        assemblyName), ex);
}
finally
{
    distributorConn.Disconnect();
}
' Specify the Distributor name and business logic properties.
Dim distributorName As String = publisherInstance
Dim assemblyName As String = "C:\Program Files\Microsoft SQL Server\110\COM\CustomLogic.dll"
Dim className As String = "Microsoft.Samples.SqlServer.BusinessLogicHandler.OrderEntryBusinessLogicHandler"
Dim friendlyName As String = "OrderEntryLogic"

Dim distributor As ReplicationServer
Dim customLogic As BusinessLogicHandler

' Create a connection to the Distributor.
Dim distributorConn As ServerConnection = New ServerConnection(distributorName)

Try
    ' Connect to the Distributor.
    distributorConn.Connect()

    ' Set the Distributor properties.
    distributor = New ReplicationServer(distributorConn)

    ' Set the business logic handler properties.
    customLogic = New BusinessLogicHandler()
    customLogic.DotNetAssemblyName = assemblyName
    customLogic.DotNetClassName = className
    customLogic.FriendlyName = friendlyName
    customLogic.IsDotNetAssembly = True

    Dim isRegistered As Boolean = False

    ' Check if the business logic handler is already registered at the Distributor.
    For Each registeredLogic As BusinessLogicHandler _
    In distributor.EnumBusinessLogicHandlers
        If registeredLogic Is customLogic Then
            isRegistered = True
        End If
    Next

    ' Register the custom logic.
    If Not isRegistered Then
        distributor.RegisterBusinessLogicHandler(customLogic)
    End If
Catch ex As Exception
    ' Do error handling here.
    Throw New ApplicationException(String.Format( _
     "The {0} assembly could not be registered.", _
     assemblyName), ex)
Finally
    distributorConn.Disconnect()
End Try

Tento příklad změní existující článek, aby používal obslužnou rutinu pro obchodní logiku.

// Define the Publisher, publication, and article names.
string publisherName = publisherInstance;
string publicationName = "AdvWorksSalesOrdersMerge";
string publicationDbName = "AdventureWorks2022";
string articleName = "SalesOrderHeader";

// Set the friendly name of the business logic handler.
string customLogic = "OrderEntryLogic";

MergeArticle article = new MergeArticle();

// Create a connection to the Publisher.
ServerConnection conn = new ServerConnection(publisherName);

try
{
    // Connect to the Publisher.
    conn.Connect();

    // Set the required properties for the article.
    article.ConnectionContext = conn;
    article.Name = articleName;
    article.DatabaseName = publicationDbName;
    article.PublicationName = publicationName;

    // Load the article properties.
    if (article.LoadProperties())
    {
        article.ArticleResolver = customLogic;
    }
    else
    {
        // Throw an exception of the article does not exist.
        throw new ApplicationException(String.Format(
        "{0} is not published in {1}", articleName, publicationName));
    }
    
}
catch (Exception ex)
{
    // Do error handling here and rollback the transaction.
    throw new ApplicationException(String.Format(
        "The business logic handler {0} could not be associated with " +
        " the {1} article.",customLogic,articleName), ex);
}
finally
{
    conn.Disconnect();
}
' Define the Publisher, publication, and article names.
Dim publisherName As String = publisherInstance
Dim publicationName As String = "AdvWorksSalesOrdersMerge"
Dim publicationDbName As String = "AdventureWorks2022"
Dim articleName As String = "SalesOrderHeader"

' Set the friendly name of the business logic handler.
Dim customLogic As String = "OrderEntryLogic"

Dim article As MergeArticle = New MergeArticle()

' Create a connection to the Publisher.
Dim conn As ServerConnection = New ServerConnection(publisherName)

Try
    ' Connect to the Publisher.
    conn.Connect()

    ' Set the required properties for the article.
    article.ConnectionContext = conn
    article.Name = articleName
    article.DatabaseName = publicationDbName
    article.PublicationName = publicationName

    ' Load the article properties.
    If article.LoadProperties() Then
        article.ArticleResolver = customLogic
    Else
        ' Throw an exception of the article does not exist.
        Throw New ApplicationException(String.Format( _
         "{0} is not published in {1}", articleName, publicationName))
    End If

Catch ex As Exception
    ' Do error handling here and rollback the transaction.
    Throw New ApplicationException(String.Format( _
     "The business logic handler {0} could not be associated with " + _
     " the {1} article.", customLogic, articleName), ex)
Finally
    conn.Disconnect()
End Try