Implementar um manipulador de lógica de negócios para um artigo de mesclagem
Aplica-se: SQL Server
Este tópico descreve como implementar um manipulador de lógica de negócios para um artigo de mesclagem no SQL Server usando programação de replicação ou RMO (Replication Management Objects).
O namespace Microsoft.SqlServer.Replication.BusinessLogicSupport implementa uma interface que permite gravar lógicas comerciais complexas para manipular eventos que ocorrem durante o processo de sincronização da replicação de mesclagem. Os métodos do manipulador de lógica de negócios podem ser invocados pelo processo de replicação para cada linha alterada que seja replicada durante a sincronização.
O processo geral para implementar um manipulador de lógica de negócios é:
Crie o assembly de manipulador de lógica comercial.
Registre o assembly no Distribuidor.
Implante o assembly no servidor em que o Merge Agent executa. Para uma assinatura pull o agente é executado no Assinante e para uma assinatura push envio o agente é executado no Distribuidor. Durante o uso da sincronização da Web, o agente é executado no servidor da Web.
Crie um artigo que usa o manipulador de lógica de negócios ou modifique um artigo existente para usar o manipulador de lógica de negócios.
O manipulador de lógica de negócios que você especificar será executado para cada linha que for sincronizada. A lógica complexa e as chamadas para outros aplicativos ou serviços de rede podem comprometer o desempenho. Para mais informações sobre manipuladores de lógica de negócios, consulte Executar lógica de negócios durante a sincronização de mesclagem.
Neste tópico
Para implementar um manipulador de lógica de negócios para um artigo de mesclagem, usando:
Usando a programação de replicação
Para criar e implantar um manipulador de lógica de negócios
No Microsoft Visual Studio, crie um novo projeto para o assembly .NET que contém o código que implementa o manipulador de lógica de negócios.
Adicione referências ao projeto para os seguintes namespaces.
Referência de assembly Location Microsoft.SqlServer.Replication.BusinessLogicSupport C:\Program Files\Microsoft SQL Server\nnn\COM (instalação padrão) System.Data GAC (componente do .NET Framework) System.Data.Common GAC (componente do .NET Framework) Adicione uma classe que substitua a classe BusinessLogicModule .
Implemente a propriedade HandledChangeStates para indicar os tipos de alterações que são controladas.
Substitua um ou mais dos seguintes métodos da classe BusinessLogicModule :
CommitHandler - invocado quando uma alteração de dados é confirmada durante sincronização.
DeleteErrorHandler - invocado ao ocorrer um erro enquanto uma instrução DELETE é carregada ou baixada.
DeleteHandler - invocado quando instruções DELETE são carregadas ou baixadas.
InsertErrorHandler - invocado ao acontecer um erro enquanto uma instrução INSERT é carregada ou baixada.
InsertHandler - invocado quando instruções INSERT são carregadas ou baixadas.
UpdateConflictsHandler - invocado quando ocorrem instruções UPDATE conflitantes no Publicador ou Assinante.
UpdateDeleteConflictHandler - invocado quando instruções UPDATE entram em conflito com instruções DELETE no Publicador e no Assinante.
UpdateErrorHandler - invocado ao ocorrer um erro enquanto uma instrução UPDATE é carregada ou baixada.
UpdateHandler - invocado quando instruções UPDATE são carregadas ou baixadas.
Construa o projeto para criar o assembly de manipulador de lógica de negócios.
Implante o assembly no diretório que contém o arquivo executável do Agente de Mesclagem (replmerg.exe), que para uma instalação padrão é C:\Program Files\Microsoft SQL Server\nnn\COM, ou instale-o no cache de assembly global (GAC) do .NET. O assembly só deve ser instalado no GAC se outros aplicativos, além do Merge Agent, exigirem acesso para o assembly. O assembly pode ser instalado no GAC por meio da ferramenta de cache de assembly global (Gacutil.exe) fornecida no .NET Framework SDK.
Observação
O manipulador de lógica de negócios precisa ser implantado em todos os servidores em que o Merge Agent é executado, incluindo-se o servidor IIS que hospeda o replisapi.dll durante o uso da sincronização da Web.
Para registrar um manipulador de lógica de negócios
No Publicador, execute sp_enumcustomresolvers (Transact-SQL) para verificar se o assembly ainda não foi registrado como manipulador de lógica de negócios.
No Distribuidor, execute sp_registercustomresolver (Transact-SQL) especificando um nome amigável para o manipulador de lógica de negócios de article_resolver, um valor igual a true em is_dotnet_assembly, o nome do assembly em dotnet_assembly_name e o nome totalmente qualificado da classe que substitui BusinessLogicModule em dotnet_class_name.
Observação
Se o assembly não for implantado no mesmo diretório do executável do Merge Agent, no mesmo diretório do aplicativo que inicia sincronicamente o Merge Agent ou no cache de assembly global (GAC), será necessário especificar o caminho completo com o nome do assembly para @dotnet_assembly_name. Ao usar a sincronização da Web, especifique o local do assembly no servidor da Web.
Para usar um manipulador de lógica de negócios com um novo artigo de tabela
- Execute sp_addmergearticle (Transact-SQL) para definir um artigo especificando o nome amigável do manipulador de lógica de negócios em @article_resolver. Para obter mais informações, consulte Define an Article.
Para usar um manipulador de lógica de negócios com um artigo de tabela existente
- Execute sp_changemergearticle (Transact-SQL) especificando @publication, @article, um valor igual a article_resolver em @property e o nome amigável do manipulador de lógica de negócios em @value.
Exemplos (programação de replicação)
Esse exemplo mostra um manipulador de lógica de negócios que cria um log de auditoria.
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
O exemplo a seguir registra um assembly de manipulador de lógica de negócios no Distribuidor e altera um artigo de mesclagem existente para usar essa lógica de negócios personalizada.
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
Usando o RMO (Replication Management Objects)
Para criar um manipulador de lógica de negócios
No Microsoft Visual Studio, crie um novo projeto para o assembly .NET que contém o código que implementa o manipulador de lógica de negócios.
Adicione referências ao projeto para os seguintes namespaces.
Referência de assembly Location Microsoft.SqlServer.Replication.BusinessLogicSupport C:\Program Files\Microsoft SQL Server\nnn\COM (instalação padrão) System.Data GAC (componente do .NET Framework) System.Data.Common GAC (componente do .NET Framework) Adicione uma classe que substitua a classe BusinessLogicModule .
Implemente a propriedade HandledChangeStates para indicar os tipos de alterações que são controladas.
Substitua um ou mais dos seguintes métodos da classe BusinessLogicModule :
CommitHandler - invocado quando uma alteração de dados é confirmada durante sincronização.
DeleteErrorHandler - invocado se um erro ocorrer enquanto uma instrução DELETE estiver sendo carregada ou baixada.
DeleteHandler - invocado quando instruções DELETE são carregadas ou baixadas.
InsertErrorHandler - invocado se um erro ocorrer quando uma instrução INSERT estiver sendo carregada ou baixada.
InsertHandler - invocado quando instruções INSERT são carregadas ou baixadas.
UpdateConflictsHandler - invocado quando ocorrem instruções UPDATE conflitantes no Publicador ou Assinante.
UpdateDeleteConflictHandler - invocado quando instruções UPDATE entram em conflito com instruções DELETE no Publicador e no Assinante.
UpdateErrorHandler - invocado se um erro ocorrer quando uma instrução UPDATE estiver sendo carregada ou baixada.
UpdateHandler - invocado quando instruções UPDATE são carregadas ou baixadas.
Observação
Qualquer conflito de artigo não explicitamente manipulado pela lógica corporativa personalizada que você utiliza são manipulados pelo resolvedor padrão para o artigo.
Construa o projeto para criar o assembly de manipulador de lógica de negócios.
Para registrar um manipulador de lógica de negócios
Crie uma conexão com o Distribuidor usando a classe ServerConnection .
Criar uma instância da classe ReplicationServer. Passe o ServerConnection da etapa 1.
Chame EnumBusinessLogicHandlers e verifique o objeto ArrayList retornado para assegurar que o assembly não tenha sido já registrado como um manipulador de lógica de negócios.
Criar uma instância da classe BusinessLogicHandler. Especifique as seguintes propriedades:
DotNetAssemblyName - o nome do assembly .NET. Se o assembly não estiver implantado no mesmo diretório que o executável Merge Agent, no mesmo diretório que o aplicativo que inicia de forma síncrona o Merge Agent ou no GAC, você deve incluir o caminho completo com o nome do assembly. Você deve incluir o caminho completo com o nome do assembly ao usar um manipulador de lógica de negócios com sincronização da Web.
DotNetClassName - o nome totalmente qualificado da classe que substitui BusinessLogicModule e implementa o manipulador de lógica de negócios.
FriendlyName - um nome amigável que você usa ao acessar o manipulador de lógica de negócios.
IsDotNetAssembly - um valor de true.
Para implantar um manipulador de lógica de negócios
- Implante o assembly no servidor em que o Merge Agent é executado no local do arquivo especificado quando o manipulador de lógica de negócios foi registrado no Distribuidor. Para uma assinatura pull o agente é executado no Assinante e para uma assinatura push envio o agente é executado no Distribuidor. Durante o uso da sincronização da Web, o agente é executado no servidor da Web. Se no caminho completo não tiver sido incluído com o nome do assembly quando o manipulador de lógica de negócios foi registrado, implante o assembly no mesmo diretório que o executável Merge Agent, no mesmo diretório que o aplicativo que inicia de forma síncrona o Merge Agent. Você pode instalar o assembly no GAC se houver múltiplos aplicativos que usem o mesmo assembly.
Para usar um manipulador de lógica de negócios com um novo artigo de tabela
Crie uma conexão com o Publicador usando a classe ServerConnection .
Criar uma instância da classe MergeArticle. Defina as seguintes propriedades:
Nome do artigo para Name.
O nome da publicação para PublicationName.
O nome do banco de dados de publicação para DatabaseName.
O nome amigável do manipulador de lógica de negócios (FriendlyName) para ArticleResolver.
Chame o método Create . Para obter mais informações, consulte Define an Article.
Para usar um manipulador de lógica de negócios com um artigo de tabela existente
Crie uma conexão com o Publicador usando a classe ServerConnection .
Criar uma instância da classe MergeArticle.
Defina as propriedades Name, PublicationNamee DatabaseName .
Defina a conexão da etapa 1 para a propriedade ConnectionContext .
Chame o método LoadProperties para obter as propriedades do objeto. Se esse método retornar false, as propriedades de artigo na etapa 3 foram definidas incorretamente ou o artigo não existe. Para obter mais informações, consulte View and Modify Article Properties.
Defina o nome amigável do manipulador de lógica de negócios para ArticleResolver. Esse é o valor da propriedade FriendlyName especificada ao registrar o manipulador de lógica de negócios.
Exemplos (RMO)
Este exemplo é um manipulador de lógica de negócios que realiza log de informações sobre inserções, atualizações e exclusões no Assinante.
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
Este exemplo registra um manipulador de lógica de negócios no Distribuidor.
// 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
Este exemplo altera um artigo existente para usar o manipulador de lógica de negócios.
// 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