Definir uma relação de registro lógico entre artigos da tabela de mesclagem

Aplica-se a: SQL Server

Este tópico descreve como definir uma relação de registro lógico entre artigos de tabela de mesclagem no SQL Server usando o SQL Server Management Studio, o Transact-SQL ou o RMO (Replication Management Objects).

A replicação de mesclagem permite definir uma relação entre linhas relacionadas em tabelas diferentes. Essas linhas podem então ser processadas como uma unidade transacional durante a sincronização. Um registro lógico pode ser definido entre dois artigos se eles tiverem ou não uma relação de filtro de junção. Para obter mais informações, consulte Agrupar alterações a linhas relacionadas com registros lógicos.

Observação

Esse recurso será removido em uma versão futura do SQL Server. Evite usar esse recurso em desenvolvimentos novos e planeje modificar os aplicativos que atualmente o utilizam.

Neste tópico

Antes de começar

Limitações e Restrições

  • Se você adicionar, modificar ou excluir um registro lógico após a inicialização de assinaturas na publicação, será preciso gerar um novo instantâneo e reinicializar todas as assinaturas depois de fazer a alteração. Para obter mais informações sobre os requisitos para alterações de propriedades, consulte Alterar propriedades da publicação e do artigo.

Como usar o SQL Server Management Studio.

Defina registros lógicos na caixa de diálogo Adicionar Junção, disponível no Assistente para Nova Publicação e na caixa de diálogo Propriedades da Publicação – <Publicação>. Para obter mais informações sobre como usar o assistente e acessar a caixa de diálogo, consulte Criar uma publicação e Exibir e modificar as propriedades da publicação.

Os registros lógicos podem ser definidos na caixa de diálogo Adicionar Junção apenas se aplicados a um filtro de junção em uma publicação de mesclagem, e se a publicação atender os requisitos para uso de partições pré-calculadas. Para definir os registros lógicos que não se aplicam a filtros de junção e para definir a detecção e resolução de conflitos no nível do registro lógico, é preciso usar procedimentos armazenados.

Para definir uma relação de registro lógico.

  1. Na página Filtrar Linhas da Tabela do Assistente para Nova Publicação ou na página Filtrar Linhas da caixa de diálogo Propriedades da Publicação – <Publicação>, selecione um filtro no painel Tabelas Filtradas.

    Uma relação de registro lógico é associada a um filtro de junção que estende um filtro de linha. Por isso, é preciso definir o filtro de linha antes de poder estender o filtro com uma junção e aplicar uma relação de registro lógico. Após definir o filtro de junção é possível estendê-lo com outro filtro de junção. Para obter mais informações sobre como definir filtros de junção, consulte Definir e modificar um filtro de junção entre artigos de mesclagem.

  2. Clique em Adicionare depois, em Adicionar Junção para Estender o Filtro Selecionado.

  3. Defina um filtro de junção na caixa de diálogo Adicionar Junção , depois marque a caixa de seleção Registro Lógico.

  4. Se você estiver na caixa de diálogo Propriedades da Publicação – <Publicação>, clique em OK para salvar e fechar a caixa de diálogo.

Para excluir uma relação de registro lógico

  • Exclua apenas a relação de registro lógico ou exclua a relação de registro lógico e o filtro de junção a ela associado.

    Para excluir apenas a relação de registro lógico:

    1. Na página Filtrar Linhas do Assistente para Nova Publicação ou na página Filtrar Linhas da caixa de diálogo Propriedades da Publicação – <Publicação>, selecione o filtro de junção associado à relação de registo lógico no painel Tabelas Filtradas e clique em Editar.

    2. Na caixa de diálogo Editar Junção , desmarque o caixa de seleção Registro Lógico.

    3. Selecione OK.

    Para excluir a relação de registro lógico e o filtro de junção a ela associado:

    • Na página Filtrar Linhas do Assistente para Nova Publicação ou na caixa de diálogo Propriedades da Publicação – <Publicação>, selecione um filtro no painel Tabelas Filtradas e, em seguida, clique em Excluir. Caso o próprio filtro excluído seja estendido por outras junções, essas junções também serão excluídas.

Usando o Transact-SQL

É possível especificar relações de registro lógico de forma programática entre artigos que usem procedimentos armazenados de replicação.

Para definir uma relação de registro lógico sem filtro de junção associado

  1. Se a publicação contiver quaisquer artigos filtrados, execute sp_helpmergepublication, e observe o valor de use_partition_groups no conjunto de resultados.

    • Se o valor for 1, partições pré-computadas já estarão sendo usadas.

    • Se o valor for 0, execute sp_changemergepublication ao Publicador do banco de dados de publicação. Especifique um valor de use_partition_groups para @property e um valor de true para @value.

      Observação

      Se a publicação não oferecer suporte a partições pré-computadas, os registros lógicos não poderão ser usados. Para obter mais informações, consulte Requisitos para usar partições pré-computadas no tópico Otimizar o desempenho de filtro parametrizado com partições pré-computadas.

    • Se o valor for NULL, será necessário executar o Snapshot Agent para gerar o instantâneo inicial para a publicação.

  2. Se os artigos que integrarem o registro lógico não existirem, execute sp_addmergearticle no Publicador do banco de dados de publicação. Especifique uma das opções de detecção e resolução de conflitos para o registro lógico:

    • Para detectar e resolver conflitos que ocorrem dentro das linhas relacionadas no registro lógico, especifique um valor de true para @logical_record_level_conflict_detection e @logical_record_level_conflict_resolution.

    • Para usar a detecção e resolução de conflitos padrão de linha ou coluna, especifique o valor de false para @logical_record_level_conflict_detection e @logical_record_level_conflict_resolution, que é o padrão.

  3. Repita a Etapa 2 para cada artigo que integrará o registro lógico. É preciso usar a mesma opção de detecção e resolução de conflitos para cada artigo no registro lógico. Para obter mais informações, consulte Detectando e resolvendo conflitos em registros lógicos.

  4. No Publicador do banco de dados de publicação, execute sp_addmergefilter. Especifique @publication; o nome do artigo na relação para @article; o nome do segundo artigo para @join_articlename; o nome da relação para @filtername; a cláusula que define a relação entre os dois artigos para @join_filterclause; o tipo de junção para @join_unique_key e um dos valores a seguir para @filter_type:

    • 2 - Define uma relação lógica.

    • 3 - Define uma relação lógica com um filtro de junção.

    Observação

    Se um filtro de junção não for usado, a direção da relação entre os dois artigos não será importante.

  5. Repita a Etapa 2 para cada relação de registro lógico remanescente na publicação.

Para alterar a detecção e resolução de conflito para registros lógicos

  1. Para detectar e resolver conflitos que ocorrem dentro de linhas relacionadas no registro lógico:

    • No Publicador do banco de dados de publicação, execute sp_changemergearticle. Especifique um valor de logical_record_level_conflict_detection para @property , e um valor de true para @value. Especifique um valor de 1 para @force_invalidate_snapshot e @force_reinit_subscription.

    • No Publicador do banco de dados de publicação, execute sp_changemergearticle. Especifique um valor de logical_record_level_conflict_resolution para @property , e um valor de true para @value. Especifique um valor de 1 para @force_invalidate_snapshot e @force_reinit_subscription.

  2. Para usar a detecção e resolução de conflitos padrão em nível de linha ou coluna:

    • No Publicador do banco de dados de publicação, execute sp_changemergearticle. Especifique um valor de logical_record_level_conflict_detection para @property , e um valor de true para @value. Especifique um valor de 1 para @force_invalidate_snapshot e @force_reinit_subscription.

    • No Publicador do banco de dados de publicação, execute sp_changemergearticle. Especifique um valor de logical_record_level_conflict_resolution para @property , e um valor de false para @value. Especifique um valor de 1 para @force_invalidate_snapshot e @force_reinit_subscription.

Para remover uma relação de registro lógico.

  1. No Publicador do banco de dados de publicação, execute a consulta a seguir para retornar informações sobre todos as relações de registro lógicos definidos para a publicação especificada:

    SELECT f.* FROM sysmergesubsetfilters AS f 
    INNER JOIN sysmergepublications AS p
    ON f.pubid = p.pubid WHERE p.[name] = @publication;
    

    Anote o nome da relação de registro lógico sendo removido da coluna filtername no conjunto de resultados.

    Observação

    Essa consulta retorna as mesmas informações de sp_helpmergefilter; no entanto, esse procedimento armazenado de sistema retorna apenas informações sobre relações de registro lógico que são também filtros de junção.

  2. No Publicador do banco de dados de publicação, execute sp_dropmergefilter. Especifique @publication, o nome de um dos artigos da relação para @article, e o nome da relação da Etapa 1 para @filtername.

Exemplo (Transact-SQL)

Esse exemplo habilita partições pré-computadas em uma publicação existente e cria um registro lógico que inclui os dois novos artigos para as tabelas SalesOrderHeader e SalesOrderDetail .

-- Remove ON DELETE CASCADE from FK_SalesOrderDetail_SalesOrderHeader_SalesOrderID;
-- logical records cannot be used with ON DELETE CASCADE. 
IF EXISTS (SELECT * FROM sys.objects 
WHERE name = 'FK_SalesOrderDetail_SalesOrderHeader_SalesOrderID')
BEGIN
    ALTER TABLE [Sales].[SalesOrderDetail] 
    DROP CONSTRAINT [FK_SalesOrderDetail_SalesOrderHeader_SalesOrderID] 
END

ALTER TABLE [Sales].[SalesOrderDetail]  
WITH CHECK ADD CONSTRAINT [FK_SalesOrderDetail_SalesOrderHeader_SalesOrderID] 
FOREIGN KEY([SalesOrderID])
REFERENCES [Sales].[SalesOrderHeader] ([SalesOrderID])
GO

DECLARE @publication    AS sysname;
DECLARE @table1 AS sysname;
DECLARE @table2 AS sysname;
DECLARE @table3 AS sysname;
DECLARE @salesschema AS sysname;
DECLARE @hrschema AS sysname;
DECLARE @filterclause AS nvarchar(1000);
DECLARE @partitionoption AS bit;
SET @publication = N'AdvWorksSalesOrdersMerge'; 
SET @table1 = N'SalesOrderDetail'; 
SET @table2 = N'SalesOrderHeader'; 
SET @salesschema = N'Sales';
SET @hrschema = N'HumanResources';
SET @filterclause = N'Employee.LoginID = HOST_NAME()';

-- Ensure that the publication uses precomputed partitions.
SET @partitionoption = (SELECT [use_partition_groups] FROM sysmergepublications 
    WHERE [name] = @publication);
IF @partitionoption <> 1
BEGIN
    EXEC sp_changemergepublication 
        @publication = @publication, 
        @property = N'use_partition_groups', 
        @value = 'true',
        @force_invalidate_snapshot = 1;
END  

-- Add a filtered article for the Employee table.
EXEC sp_addmergearticle 
  @publication = @publication, 
  @article = @table1, 
  @source_object = @table1, 
  @type = N'table', 
  @source_owner = @hrschema,
  @schema_option = 0x0004CF1,
  @description = N'article for the Employee table',
  @subset_filterclause = @filterclause;

-- Add an article for the SalesOrderHeader table.
EXEC sp_addmergearticle 
  @publication = @publication, 
  @article = @table2, 
  @source_object = @table2, 
  @type = N'table', 
  @source_owner = @salesschema,
  @schema_option = 0x0034EF1,
  @description = N'article for the SalesOrderHeader table';

-- Add an article for the SalesOrderDetail table.
EXEC sp_addmergearticle 
  @publication = @publication, 
  @article = @table3, 
  @source_object = @table3, 
  @source_owner = @salesschema,
  @description = 'article for the SalesOrderDetail table', 
  @identityrangemanagementoption = N'auto', 
  @pub_identity_range = 100000, 
  @identity_range = 100, 
  @threshold = 80;

-- Add a merge join filter between Employee and SalesOrderHeader.
EXEC sp_addmergefilter 
  @publication = @publication, 
  @article = @table2, 
  @filtername = N'SalesOrderHeader_Employee', 
  @join_articlename = @table1, 
  @join_filterclause = N'Employee.EmployeeID = SalesOrderHeader.SalesPersonID', 
  @join_unique_key = 1, 
  @filter_type = 1, 
  @force_invalidate_snapshot = 1, 
  @force_reinit_subscription = 1;

-- Create a logical record relationship that is also a merge join 
-- filter between SalesOrderHeader and SalesOrderDetail.
EXEC sp_addmergefilter 
  @publication = @publication, 
  @article = @table3, 
  @filtername = N'LogicalRecord_SalesOrderHeader_SalesOrderDetail', 
  @join_articlename = @table2, 
  @join_filterclause = N'[SalesOrderHeader].[SalesOrderID] = [SalesOrderDetail].[SalesOrderID]', 
  @join_unique_key = 1, 
  @filter_type = 3, 
  @force_invalidate_snapshot = 1, 
  @force_reinit_subscription = 1;
GO

Usando o RMO (Replication Management Objects)

Observação

A replicação de mesclagem lhe permite também especificar que os conflitos sejam rastreados e resolvidos em nível de registro lógico, mas essas opções não podem ser definidas usando-se RMO.

Para definir uma relação de registro lógico sem filtro de junção associado

  1. Crie uma conexão com o Publicador usando a classe ServerConnection .

  2. Crie uma instância da classe MergePublication , defina Name e propriedades DatabaseName para a publicação, e defina a propriedade ConnectionContext para a conexão criada no etapa 1.

  3. Chame o método LoadProperties para obter as propriedades do objeto. Se esse método retornar false, as propriedades de publicação na etapa 2 foram definidas incorretamente ou a publicação não existe.

  4. Se a propriedade PartitionGroupsOption for definida como False, defina-a para True.

  5. Se os artigos que farão parte do registro lógico não existem, crie uma instância de classe MergeArticle e defina as seguintes propriedades:

    • Nome do artigo para Name.

    • O nome da publicação para PublicationName.

    • (Opcional) Se o artigo for filtrado horizontalmente, especifique a cláusula do filtro da linha para a propriedade FilterClause . Use essa propriedade para especificar um filtro de linha estático ou com parâmetros. Para obter mais informações, consulte Filtros de linha com parâmetros.

    Para obter mais informações, consulte Define an Article.

  6. Chame o método Create .

  7. Repita a etapa 5 e 6 para cada artigo que integra o registro lógico.

  8. Crie uma instância da classe MergeJoinFilter para definir a relação de registro lógica entre artigos. Em seguida, defina as seguintes propriedades:

  9. Chame o método AddMergeJoinFilter no objeto que representa o artigo filho na relação. Passe o objeto MergeJoinFilter da etapa 8 para definir a relação.

  10. Repita as etapas 8 e 9 para cada relação de registro lógico remanescente na publicação.

Exemplo (RMO)

Esse exemplo cria um registro lógico que inclui os dois novos artigos para as tabelas SalesOrderHeader e SalesOrderDetail .

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

           // Specify article names.
           string articleName1 = "SalesOrderHeader";
           string articleName2 = "SalesOrderDetail";
           
           // Specify logical record information.
           string lrName = "SalesOrderHeader_SalesOrderDetail";
           string lrClause = "[SalesOrderHeader].[SalesOrderID] = "
               + "[SalesOrderDetail].[SalesOrderID]";

           string schema = "Sales";

           MergeArticle article1 = new MergeArticle();
           MergeArticle article2 = new MergeArticle();
           MergeJoinFilter lr = new MergeJoinFilter();
           MergePublication publication = new MergePublication();

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

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

               // Verify that the publication uses precomputed partitions.
               publication.Name = publicationName;
               publication.DatabaseName = publicationDbName;
               publication.ConnectionContext = conn;

               // If we can't get the properties for this merge publication, then throw an application exception.
               if (publication.LoadProperties())
               {
                   // If precomputed partitions is disabled, enable it.
                   if (publication.PartitionGroupsOption == PartitionGroupsOption.False)
                   {
                       publication.PartitionGroupsOption = PartitionGroupsOption.True;
                   }
               }
               else
               {
                   throw new ApplicationException(String.Format(
                       "Settings could not be retrieved for the publication. " +
                       "Ensure that the publication {0} exists on {1}.",
                       publicationName, publisherName));
               }

               // Set the required properties for the PurchaseOrderHeader article.
               article1.ConnectionContext = conn;
               article1.Name = articleName1;
               article1.DatabaseName = publicationDbName;
               article1.SourceObjectName = articleName1;
               article1.SourceObjectOwner = schema;
               article1.PublicationName = publicationName;
               article1.Type = ArticleOptions.TableBased;

               // Set the required properties for the SalesOrderDetail article.
               article2.ConnectionContext = conn;
               article2.Name = articleName2;
               article2.DatabaseName = publicationDbName;
               article2.SourceObjectName = articleName2;
               article2.SourceObjectOwner = schema;
               article2.PublicationName = publicationName;
               article2.Type = ArticleOptions.TableBased;

               if (!article1.IsExistingObject) article1.Create();
               if (!article2.IsExistingObject) article2.Create();

               // Define a logical record relationship between 
               // PurchaseOrderHeader and PurchaseOrderDetail. 

               // Parent article.
               lr.JoinArticleName = articleName1;
               
               // Child article.
               lr.ArticleName = articleName2;
               lr.FilterName = lrName;
               lr.JoinUniqueKey = true;
               lr.FilterTypes = FilterTypes.LogicalRecordLink;
               lr.JoinFilterClause = lrClause;

               // Add the logical record definition to the parent article.
               article1.AddMergeJoinFilter(lr);
           }
           catch (Exception ex)
           {
               // Do error handling here and rollback the transaction.
               throw new ApplicationException(
                   "The filtered articles could not be created", ex);
           }
           finally
           {
               conn.Disconnect();
           }
' Define the Publisher and publication names.
Dim publisherName As String = publisherInstance
Dim publicationName As String = "AdvWorksSalesOrdersMerge"
Dim publicationDbName As String = "AdventureWorks2022"

' Specify article names.
Dim articleName1 As String = "SalesOrderHeader"
Dim articleName2 As String = "SalesOrderDetail"

' Specify logical record information.
Dim lrName As String = "SalesOrderHeader_SalesOrderDetail"
Dim lrClause As String = "[SalesOrderHeader].[SalesOrderID] = " _
        & "[SalesOrderDetail].[SalesOrderID]"

Dim schema As String = "Sales"

Dim article1 As MergeArticle = New MergeArticle()
Dim article2 As MergeArticle = New MergeArticle()
Dim lr As MergeJoinFilter = New MergeJoinFilter()
Dim publication As MergePublication = New MergePublication()

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

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

    ' Verify that the publication uses precomputed partitions.
    publication.Name = publicationName
    publication.DatabaseName = publicationDbName
    publication.ConnectionContext = conn

    ' If we can't get the properties for this merge publication, then throw an application exception.
    If publication.LoadProperties() Then
        ' If precomputed partitions is disabled, enable it.
        If publication.PartitionGroupsOption = PartitionGroupsOption.False Then
            publication.PartitionGroupsOption = PartitionGroupsOption.True
        End If
    Else
        Throw New ApplicationException(String.Format( _
            "Settings could not be retrieved for the publication. " _
            & "Ensure that the publication {0} exists on {1}.", _
            publicationName, publisherName))
    End If

    ' Set the required properties for the SalesOrderHeader article.
    article1.ConnectionContext = conn
    article1.Name = articleName1
    article1.DatabaseName = publicationDbName
    article1.SourceObjectName = articleName1
    article1.SourceObjectOwner = schema
    article1.PublicationName = publicationName
    article1.Type = ArticleOptions.TableBased

    ' Set the required properties for the SalesOrderDetail article.
    article2.ConnectionContext = conn
    article2.Name = articleName2
    article2.DatabaseName = publicationDbName
    article2.SourceObjectName = articleName2
    article2.SourceObjectOwner = schema
    article2.PublicationName = publicationName
    article2.Type = ArticleOptions.TableBased

    If Not article1.IsExistingObject Then
        article1.Create()
    End If
    If Not article2.IsExistingObject Then
        article2.Create()
    End If

    ' Define a logical record relationship between 
    ' SalesOrderHeader and SalesOrderDetail. 

    ' Parent article.
    lr.JoinArticleName = articleName1
    ' Child article.
    lr.ArticleName = articleName2
    lr.FilterName = lrName
    lr.JoinUniqueKey = True
    lr.FilterTypes = FilterTypes.LogicalRecordLink
    lr.JoinFilterClause = lrClause

    ' Add the logical record definition to the parent article.
    article1.AddMergeJoinFilter(lr)
Catch ex As Exception
    ' Do error handling here and rollback the transaction.
    Throw New ApplicationException( _
            "The filtered articles could not be created", ex)
Finally
    conn.Disconnect()
End Try