Partilhar via


Como provisionar um banco de dados de servidor para sincronização de colaboração (não SQL Server)

Dica

Os tópicos desta seção da documentação, Sincronizando outros bancos de dados compatíveis com ADO.NET, foram criados para demonstrar como bancos de dados diferentes do SQL Server podem ser sincronizados usando o Sync Framework. Nesta versão, o SQL Server é usado em exemplos de código, mas o código pode ser usado para outros bancos de dados compatíveis do ADO.NET, com algumas modificações nos objetos específicos do SQL Server (como SqlConnection) e nas consultas SQL mostradas. Para obter informações sobre a sincronização do SQL Server, consulte Como configurar e executar a sincronização de bancos de dados (SQL Server).

Este tópico descreve como provisionar um banco de dados sincronizado por DbSyncProvider, de modo que as alterações de dados incrementais no banco de dados possam ser controladas. As alterações são controladas para que possam ser aplicadas a outros nós durante a sessão de sincronização. Para provisionar um banco de dados para o Sync Framework, siga estas etapas:

  1. Habilite o isolamento do instantâneo para o banco de dados

  2. Identifique as tabelas a serem sincronizadas

  3. Crie tabelas de controle para armazenar metadados por tabela e crie índices nessas tabelas

  4. Crie gatilhos em cada tabela base para popular e atualizar as tabelas de controle

  5. (Opcional) Trate dados existentes no banco de dados

  6. Crie uma tabela de controle para armazenar metadados por escopo e crie um índice nessa tabela

  7. Defina escopos a serem sincronizados, o que especifica quais tabelas são sincronizadas como uma unidade

  8. Crie procedimentos armazenados para selecionar e atualizar dados e metadados

Essas etapas não são necessárias para bancos de dados sincronizados por SqlCeSyncProvider; o provisionamento é manipulado pelo Sync Framework quando o banco de dados é inicializado.

Depois de ser provisionado, um banco de dados pode ser sincronizado com outros nós. Para obter mais informações sobre como configurar e executar uma sincronização, consulte Como configurar e executar a sincronização de colaboração (não SQL Server).

Habilitar o isolamento do instantâneo para o banco de dados

Durante a fase de enumeração da alteração de uma sessão de sincronização, o Sync Framework inicia transações sob isolamento do instantâneo. Para iniciar transações sob isolamento do instantâneo, você deve definir a opção de banco de dados ALLOW_SNAPSHOT_ISOLATION como ON, conforme mostrado no exemplo de código a seguir:

ALTER DATABASE [database name] SET ALLOW_SNAPSHOT_ISOLATION ON

Para obter mais informações, consulte os Manuais Online do SQL Server.

Identificar tabelas a serem sincronizadas

A primeira etapa no provisionamento do banco de dados é identificar as tabelas que serão sincronizadas. Cada tabela deve ter uma chave primária. Considere o exemplo de código a seguir. Ele mostra o esquema de tabela Sales.Customer no banco de dados SyncSamplesDb_Peer1.

    CREATE TABLE Sales.Customer(
        CustomerId uniqueidentifier NOT NULL PRIMARY KEY DEFAULT NEWID(), 
        CustomerName nvarchar(100) NOT NULL,
        SalesPerson nvarchar(100) NOT NULL,
        CustomerType nvarchar(100) NOT NULL)

Cada tabela que você sincroniza tem um objeto DbSyncAdapter associado, e você especifica a chave primária na coleção RowIdColumns do objeto. Para obter mais informações, consulte Como configurar e executar a sincronização de colaboração (não SQL Server).

As tabelas podem estar vazias ou podem conter dados existentes. Se a tabela contiver linhas de dados existentes que devem ser sincronizadas, você precisará assegurar que cada linha tenha uma entrada de metadados na tabela apropriada de controle de alterações. Para obter mais informações, consulte Tratar dados existentes no banco de dados.

Criar tabelas de controle para metadados por tabela

O Sync Framework requer uma forma de controlar quais linhas foram alteradas desde a sessão de sincronização anterior entre dois nós. As alterações são representadas por dois tipos diferentes de metadados:

  • Metadados por tabela, que controlam operações de inserção, atualização e exclusão de cada tabela sincronizada.

  • Metadados por escopo, que controlam quais alterações cada nó recebeu de outros nós.

Os metadados por tabela são controlados por meio do uso de uma tabela de controle para cada tabela base. A tabela base e as tabelas de controle devem estar presentes em cada banco de dados que é sincronizado por DbSyncProvider. A chave primária da tabela de controle é a mesma que a da tabela base e são necessárias colunas adicionais. Essas colunas são descritas na tabela a seguir. Os nomes das colunas adicionais não precisam ser os mesmos que os listados, mas eles devem corresponder em ordem e tipo às consultas ou aos procedimentos que acessam as tabelas de controle. Alguns desses procedimentos estão incluídos em Criar procedimentos armazenados para selecionar e atualizar dados e metadados.

Coluna

Descrição

Atualizada quando...

<PK (Chave Primária) da tabela base> - inclua uma coluna para cada coluna de PK.

Colunas de chave primária da tabela base.

Uma linha é inserida na tabela base. A inserção pode ter origem no nó local ou remoto.

update_scope_local_id

A ID do escopo que executou a última atualização ou exclusão. Para atualizações ou exclusões que têm origem no nó local, esta coluna é NULO.

Refere-se à coluna scope_local_id na tabela de informações de escopo. Para obter mais informações, consulte "Criar tabelas de controle para metadados por escopo".

Uma atualização ou exclusão de um nó remoto é aplicada à tabela base.

scope_update_peer_key

A identidade do nó que executou a última atualização ou exclusão.

Uma atualização ou exclusão de um nó remoto é aplicada à tabela base.

scope_update_peer_timestamp

O valor do carimbo de data/hora no banco de dados remoto em que a linha foi atualizada ou excluída originalmente.

Uma atualização ou exclusão de um nó remoto é aplicada à tabela base.

local_update_peer_key

A identidade do nó local. Esta coluna conterá um valor igual a 0 para cada linha, a menos que o banco de dados local tenha sido restaurado de um backup. 1

Uma atualização ou exclusão de uma operação local ou de um nó remoto é aplicada à tabela base.

local_update_peer_timestamp

O valor do carimbo de data/hora no banco de dados local em que a linha foi atualizada ou excluída no banco de dados local. 1

Uma atualização ou exclusão de uma operação local ou de um nó remoto é aplicada à tabela base.

create_scope_local_id

A identidade do escopo que executou a inserção. Para atualizações ou exclusões que têm origem no nó local, esta coluna é NULO.

Refere-se à coluna scope_local_id na tabela de informações de escopo. Para obter mais informações, consulte "Criar tabelas de controle para metadados por escopo", em Como provisionar um banco de dados de servidor para sincronização de colaboração (não SQL Server).

Uma inserção de um nó remoto é aplicada à tabela base.

scope_create_peer_key

A identidade do nó que executou a inserção.

Uma inserção de um nó remoto é aplicada à tabela base.

scope_create_peer_timestamp

O valor do carimbo de data/hora no banco de dados remoto em que a linha foi inserida originalmente.

Uma inserção de um nó remoto é aplicada à tabela base.

local_create_peer_key

A identidade do nó local. Esta coluna conterá um valor igual a 0 para cada linha, a menos que o banco de dados local tenha sido restaurado de um backup. 1

Uma inserção de uma operação local ou de um nó remoto é aplicada à tabela base.

local_create_peer_timestamp

O valor do carimbo de data/hora no banco de dados local em que a linha foi inserida no banco de dados local. 1

Uma inserção de uma operação local ou de um nó remoto é aplicada à tabela base.

sync_row_is_tombstone

Um valor igual a 1 indica que uma entrada de metadados é para uma exclusão na tabela base.

Uma linha é excluída da tabela base. A exclusão pode ter origem no nó local ou remoto.

last_change_datetime

A data e a hora em que a linha de metadados foi atualizada pela última vez.

Uma linha nessa tabela de controle é inserida ou atualizada.

restore_timestamp

Armazena o valor de local_update_peer_timestamp na hora de uma restauração de banco de dados. O valor é então usado como o valor de carimbo de data/hora de atualização local.

Normalmente NULO, mas pode ser definido pelo processo de restauração. Defina como NULO sempre que uma linha for atualizada.

<Colunas de filtro> - adicione uma coluna para cada coluna não PK usada na cláusula WHERE de filtragem para qualquer escopo.

Necessária somente se uma tabela for filtrada para um ou mais escopos. Armazena o valor das colunas filtradas para inserções, atualizações e exclusões.

Uma linha é inserida, atualizada ou excluída na tabela base. A exclusão pode ter origem no nó local ou remoto.

1 Usada pelo Sync Framework quando escopos sobrepostos são sincronizados. Considere o seguinte exemplo de atualizações para um banco de dados que sincroniza o escopo X com o cliente A e o escopo Y com o cliente B. Ambos os escopos contêm a linha Q.

  1. A linha Q é atualizada no cliente A e, em seguida, sincronizada com o banco de dados.

  2. O cliente B sincroniza com o banco de dados e recebe a atualização para a linha Q.

    O cliente B não reconhece o escopo X e, por isso, a alteração do cliente A deve parecer ter sido originada no banco de dados. Isso é realizado com o uso dos valores de local_update_peer_key e local_update_peer_timestamp durante a sincronização com o cliente B ou com qualquer outro cliente que não sincronize o escopo armazenado em update_scope_local_id para a linha Q.

  3. A linha Q é atualizada no banco de dados e, em seguida, sincronizada com o cliente A.

    O cliente A reconhece o escopo X e, por isso, os valores de scope_update_peer_key e scope_update_peer_timestamp são usados durante a sincronização com o cliente A ou com qualquer outro cliente que sincronize o escopo X.

É recomendável criar um esquema de banco de dados separado para a tabela de controle e todos os outros objetos relacionados aos metadados de sincronização. Isso ajuda a isolar os metadados dos dados nas tabelas base. Para um desempenho ideal, crie índices em cada tabela de controle:

  • Os dados não são filtrados: use a mesma chave primária da tabela base e crie um índice não clusterizado em (local_update_peer_timestamp)

  • Os dados são filtrados: use a mesma chave primária da tabela base e crie um índice não clusterizado em (local_update_peer_timestamp, <colunas de filtro>, <colunas de chave primária>)

Os exemplos de código a seguir criam uma tabela no esquema Sync que controla alterações na tabela Sales.Customer e adiciona um índice à tabela.

    
        CustomerId uniqueidentifier NOT NULL PRIMARY KEY,          
    
        update_scope_local_id int NULL, 
        scope_update_peer_key int,
        scope_update_peer_timestamp bigint,
        local_update_peer_key int,
        local_update_peer_timestamp timestamp,
    
        create_scope_local_id int NULL,
        scope_create_peer_key int,
        scope_create_peer_timestamp bigint,
        local_create_peer_key int,
        local_create_peer_timestamp bigint,
    
        sync_row_is_tombstone int, 
        restore_timestamp bigint, 
        last_change_datetime datetime default NULL)

    CREATE NONCLUSTERED INDEX NonClustered_Customer_Tracking
    ON Sync.Customer_Tracking ([local_update_peer_timestamp])

Depois de criar tabelas de controle, adicione um gatilho INSERT, UPDATE e DELETE a cada tabela base. Quando um usuário ou o Sync Framework insere, atualiza ou exclui uma linha em uma tabela base, um gatilho é disparado e os metadados da linha são inseridos ou atualizados na tabela de controle de alterações. Se o Sync Framework tiver aplicado a alteração à tabela base (porque veio de outro nó), o Sync Framework atualizará a tabela de controle de alterações de modo a refletir a origem da alteração.

O exemplo de código a seguir cria um gatilho que atualiza os metadados de controle de alterações na tabela Sales.Customer_Tracking quando uma atualização é feita na tabela Sales.Customer. Para obter exemplos de gatilhos de inserção e exclusão, consulte Scripts de instalação para tópicos de instruções do provedor de banco de dados.

CREATE TRIGGER Customer_UpdateTrigger ON Sales.Customer FOR UPDATE
AS    
    UPDATE t    
    SET 
        update_scope_local_id = NULL, local_update_peer_key = 0, 
        restore_timestamp = NULL, last_change_datetime = GetDate() 
    FROM Sync.Customer_Tracking t JOIN inserted i ON t.[CustomerId] = i.[CustomerId]        

Tratar dados existentes no banco de dados

Os metadados de controle de alterações de cada tabela são inseridos e atualizados por gatilhos na tabela base. Portanto, as tabelas de controle de alterações não contêm informações sobre linhas que foram inseridas em uma tabela base antes de os gatilhos serem adicionados. Para tratar dados existentes no banco de dados, os metadados devem ser inseridos para os dados existentes. Em seguida, durante a primeira sessão de sincronização, todas as linhas são enviadas como novas inserções ao banco de dados de destino. O exemplo de código a seguir mostra o comando a ser executado para cada tabela base depois de você ter adicionado gatilhos à tabela base:

    INSERT INTO [tracking table] ([pk columns], create_scope_local_id, local_create_peer_key, local_create_peer_timestamp, update_scope_local_id, local_update_peer_key, restore_timestamp, sync_row_is_tombstone)
    SELECT [pk columns], NULL, 0, @@DBTS+1, NULL, 0, NULL, 0 from [base table] baseT left outer join [tracking table] trackingT
    On baseT.[pk columns]=trackingT.[pk columns]
    where tracking.[pk columns] is null

Criar tabelas de controle para metadados por escopo

Os metadados por escopo normalmente são controlados com o uso de duas tabelas em cada banco de dados:

  • A tabela de informações de escopo armazena o conhecimento da sincronização em formato binário para cada escopo. Um escopo é um agrupamento lógico de tabelas que define quais dados devem ser sincronizados como uma unidade.

  • A tabela de mapeamento de escopo identifica quais tabelas em um banco de dados pertencem a um escopo específico. Uma tabela pode pertencer a mais de um escopo. A tabela de mapeamento deve conter uma entrada para cada par <escopo, tabela>.

O Sync Framework usa o conhecimento para determinar quais alterações devem ser enviadas a cada banco de dados durante a sincronização. Os aplicativos não precisam trabalhar diretamente com o conhecimento. Considere uma topologia de sincronização bidirecional com três nós:

  1. O Nó1 e o Nó2 sincronizam todas as alterações.

  2. O Nó1 sincroniza com o Nó3.

  3. Um usuário executa uma atualização no Nó2.

  4. O Nó3 sincroniza com o Nó2.

Quando o Nó3 sincroniza com o Nó2, o Nó3 já tem a maioria das alterações do Nó2, pois o Nó3 sincronizou primeiro com o Nó1. O conhecimento permite que o Sync Framework reconheça essa situação e sincronize apenas a atualização que ocorreu no Nó2. Para obter mais informações sobre conhecimento, consulte Noções básicas sobre conhecimento de sincronização.

As colunas da tabela de informações de escopo são descritas na tabela a seguir.

Coluna

Descrição

Atualizada quando...

scope_id

Um identificador para o escopo, normalmente um GUID.

Nunca é atualizada

scope_local_id

Um identificador de inteiro para o escopo. Deveria ser uma coluna de IDENTIDADE.

Nunca é atualizada

scope_name

O nome do escopo.

Nunca é atualizada

scope_sync_knowledge

Uma representação binária do conhecimento da sincronização para cada escopo.

Todas as alterações foram aplicadas a um destino para uma sessão de sincronização.

scope_tombstone_cleanup_knowledge

Uma representação binária do conhecimento esquecido para cada escopo. O conhecimento esquecido é usado para metadados que foram removidos.

Todas as alterações foram aplicadas a um destino para uma sessão de sincronização.

scope_timestamp

O valor do carimbo de data/hora em que a linha de metadados foi atualizada pela última vez.

Uma linha nessa tabela de controle é atualizada.

scope_cleanup_timestamp

Valor do carimbo de data/hora em que a mais recente remoção de marca de exclusão foi executada para esse escopo.

As marcas de exclusão são removidas para outro escopo que tenha tabelas sobrepostas.

O exemplo de código a seguir cria uma tabela de informações de escopo.

    CREATE TABLE Sync.ScopeInfo(       
        scope_local_id int IDENTITY(1,1),
        scope_id uniqueidentifier default NEWID(),
        scope_name nvarchar(100) NOT NULL PRIMARY KEY,
        scope_sync_knowledge varbinary(max) NULL,
        scope_tombstone_cleanup_knowledge varbinary(max) NULL,
        scope_timestamp timestamp,
        scope_cleanup_timestamp bigint)

A tabela de informações de escopo quase sempre é consultada para recuperar informações sobre um escopo específico, com base no nome do escopo. Assim, a chave primária é definida na coluna scope_name.

As colunas da tabela de mapeamento de escopo são descritas na tabela a seguir.

Coluna

Descrição

Atualizada quando...

table_name

O nome da tabela.

Nunca é atualizada

scope_name

O nome do escopo.

Nunca é atualizada

Os exemplos de código a seguir criam uma tabela de mapeamento de escopo e um índice nessa tabela.

    CREATE TABLE Sync.ScopeTableMap(     
        scope_name nvarchar(100) ,
        table_name nvarchar(100)     
        )

    CREATE UNIQUE CLUSTERED INDEX Clustered_ScopeTableMap ON Sync.ScopeTableMap(scope_name, table_name)

Definir escopos a serem sincronizados

Depois de criar as tabelas de escopo, escolha um ou mais escopos para sincronizar. Por exemplo, você pode definir um escopo chamado Sales e incluir as tabelas Customer, CustomerContact, OrderHeader e OrderDetail nesse escopo. Quando o escopo Sales for sincronizado, as alterações feitas nas quatro tabelas serão trocadas entre os dois nós. Definir um escopo é um processo de duas partes:

  1. Adicione entradas à tabela de informações de escopo e à tabela de mapeamento de escopo, como no exemplo de código a seguir.
        INSERT INTO Sync.ScopeInfo(scope_name) VALUES (''Sales'')
        INSERT INTO Sync.ScopeTableMap(scope_name, table_name) VALUES (''Sales'', ''Sales.Customer'')
        INSERT INTO Sync.ScopeTableMap(scope_name, table_name) VALUES (''Sales'', ''Sales.CustomerContact'')
  1. Especifique o nome do escopo para a propriedade ScopeName do objeto DbSyncProvider e adicione um objeto DbSyncAdapter para cada tabela que você deseja incluir no escopo. Para obter mais informações, consulte "Código de aplicativo para conexão e nome do escopo", em Como configurar e executar a sincronização de colaboração (não SQL Server).

Importante

Depois que um escopo tiver sido sincronizado pela primeira vez, ele não deverá ser alterado. A alteração das tabelas no escopo ou a filtragem de cláusulas para essas tabelas podem resultar na não convergência dos dados.

Escopos filtrados e sobrepostos

Um escopo será filtrado se apenas um subconjunto das linhas da tabela base for incluído no escopo. Por exemplo, você pode definir um escopo filtrado chamado sales-WA que contenha somente os dados de vendas para o estado de Washington. Para filtrar os dados, a consulta ou o procedimento que você especifica para a propriedade SelectIncrementalChangesCommand do objeto DbSyncAdapter deve incluir uma cláusula WHERE que seleciona os dados apropriados. A consulta ou o procedimento deve selecionar alterações com base nas colunas de filtro na tabela de rastreamento e não nas colunas de filtro na tabela base.

Não há suporte para os seguintes tipos de filtragem:

  • Filtragem de coluna: todas as colunas devem ser incluídas nas consultas ou nos procedimentos que selecionam e aplicam alterações.

  • Atualizações para colunas que são usadas para filtrar: se um usuário atualizar um valor em uma coluna que é usada para filtrar, uma linha se moverá de um escopo a outro. A linha é enviada para o novo escopo ao qual ela pertence agora, mas não é excluída do escopo antigo.

Dois escopos serão sobrepostos se compartilharem os mesmos dados. Por exemplo, a tabela products pode ser incluída em um escopo sales e em um escopo inventory. Os escopos podem ser sobrepostos e filtrados. Os seguintes cenários demonstram de que modo a filtragem e a sobreposição podem ocorrer:

  • Cenário 1:

    • O escopo 1 é sales-WA. Esse escopo inclui: products; orders, com um filtro de state=WA; e order_details, com um filtro de state=WA.

    • O escopo 2 é sales-OR. Esse escopo inclui: products; orders, com um filtro de state=OR; e order_details, com um filtro de state=OR.

    Nesse cenário, toda a tabela products é compartilhada pelos dois escopos. As tabelas orders e order_details estão em ambos os escopos, mas os filtros não se sobrepõem; portanto, os escopos não compartilham linhas dessas tabelas.

  • Cenário 2:

    • O escopo 1 é sales-WA. Esse escopo inclui: products; orders, com um filtro de state=WA; e order_details, com um filtro de state=WA.

    • O escopo 2 é sales-Northwest. Esse escopo inclui: products; orders, com um filtro de state=WA OR state=ID; e shippers.

    Nesse cenário, toda a tabela products é novamente compartilhada pelos dois escopos. A tabela orders está em ambos os escopos e os filtros se sobrepõem; ambos os escopos compartilham as linhas que correspondem ao filtro state=WA. As tabelas shippers e order_details não são compartilhadas entre os escopos.

Existem muitas maneiras diferentes de se definir escopos, mas o princípio a seguir deve ser seguido: todos os dados que são sincronizados entre um par de bancos de dados na topologia de sincronização podem pertencer a um único escopo. Por exemplo, no Cenário 2 acima, o Banco de Dados A e o Banco de Dados B poderiam sincronizar o Escopo 1; e o Banco de Dados A e o Banco de Dados C poderiam sincronizar o Escopo 2. O Banco de Dados A e o Banco de Dados B não podem sincronizar o Escopo 2 porque as linhas products e orders pertencem a ambos os escopos.

Criar procedimentos armazenados para selecionar e atualizar dados e metadados

Depois de criar tabelas de metadados, crie consultas SQL ou procedimentos armazenados (recomendado) para selecionar e aplicar alterações às tabelas base e às tabelas de metadados. Os procedimentos armazenados são recomendados por motivos de desempenho e segurança. Esses procedimentos ou consultas são especificados para os comandos DbSyncAdapter a seguir. Estes comandos são descritos em "Adaptador de sincronização", em Como configurar e executar a sincronização de colaboração (não SQL Server).

Os exemplos de código a seguir criam um conjunto de procedimentos armazenados para controlar alterações de dados e metadados da tabela Sales.Customer. Para economizar tempo, os procedimentos para selecionar dados e controlar atualizações já foram incluídos, mas os referentes a inserções e exclusões ainda não. Para obter exemplos de procedimentos de inserção e exclusão, consulte Scripts de instalação para tópicos de instruções do provedor de banco de dados. Para obter um modelo que permite criar todos esses procedimentos armazenados com mais facilidade, consulte Modelo de provisionamento de servidor (Não SQL Server).

No exemplo de código completo no fim deste tópico, muitos dos valores que são passados para esses procedimentos são provenientes de variáveis de sessão. Essas variáveis são internas e habilitam o Sync Framework para passar valores para os comandos durante uma sessão de sincronização. Para obter mais informações sobre variáveis de sessão, consulte Como usar variáveis de sessão para a sincronização de colaboração (não SQL Server).

Procedimento para SelectIncrementalChangesCommand

    create procedure Sync.sp_Customer_SelectChanges (
        @sync_min_timestamp bigint,
        @sync_metadata_only int,
        @sync_scope_local_id int,
        @sync_initialize int
    )
    as
    
    --if @sync_initialize = 0
    --begin
        -- Perform additional logic if required.
    --end
        
    begin
        select  t.CustomerId, 
                c.CustomerName,
                c.SalesPerson,
                c.CustomerType, 
                t.sync_row_is_tombstone,
                t.local_update_peer_timestamp as sync_row_timestamp, 
                case when (t.update_scope_local_id is null or t.update_scope_local_id <> @sync_scope_local_id) 
                     then case when (t.restore_timestamp is null) then t.local_update_peer_timestamp else t.restore_timestamp end else t.scope_update_peer_timestamp end as sync_update_peer_timestamp,
                case when (t.update_scope_local_id is null or t.update_scope_local_id <> @sync_scope_local_id) 
                     then t.local_update_peer_key else t.scope_update_peer_key end as sync_update_peer_key,
                case when (t.create_scope_local_id is null or t.create_scope_local_id <> @sync_scope_local_id) 
                     then t.local_create_peer_timestamp else t.scope_create_peer_timestamp end as sync_create_peer_timestamp,
                case when (t.create_scope_local_id is null or t.create_scope_local_id <> @sync_scope_local_id) 
                     then t.local_create_peer_key else t.scope_create_peer_key end as sync_create_peer_key
        from Sales.Customer c right join Sync.Customer_Tracking t on c.CustomerId = t.CustomerId
        where t.local_update_peer_timestamp > @sync_min_timestamp
    end

Procedimento para UpdateCommand

    CREATE PROCEDURE Sync.sp_Customer_ApplyUpdate (                                 
            @CustomerId uniqueidentifier,
            @CustomerName nvarchar(100),
            @SalesPerson nvarchar(100),
            @CustomerType nvarchar(100),
            @sync_min_timestamp bigint ,                                
            @sync_row_count int OUT,
            @sync_force_write int)        
    AS      
        UPDATE c
        SET c.CustomerName = @CustomerName, c.SalesPerson = @SalesPerson, c.CustomerType = @CustomerType      
        FROM Sales.Customer c JOIN Sync.Customer_Tracking t ON c.CustomerId = t.CustomerId
        WHERE ((t.local_update_peer_timestamp <= @sync_min_timestamp) OR @sync_force_write = 1)
            AND t.CustomerId = @CustomerId  
        SET @sync_row_count = @@rowcount

Procedimento para UpdateMetadataCommand

    create procedure Sync.sp_CustomerContact_UpdateMetadata (
            @CustomerId uniqueidentifier,
            @PhoneType nvarchar(100),
            @sync_scope_local_id int,
            @sync_row_is_tombstone int,
            @sync_create_peer_key int ,
            @sync_create_peer_timestamp bigint,                 
            @sync_update_peer_key int ,
            @sync_update_peer_timestamp timestamp,                      
            @sync_row_timestamp timestamp,
            @sync_check_concurrency int,        
            @sync_row_count int out)        
    as  
        declare @was_tombstone int
        select @was_tombstone = sync_row_is_tombstone from Sync.CustomerContact_Tracking 
        where CustomerId = @CustomerId and PhoneType = @PhoneType
        
        if (@was_tombstone is not null and @was_tombstone=1 and @sync_row_is_tombstone=0)
            -- tombstone is getting resurrected, update creation version as well
            update Sync.CustomerContact_Tracking set
                [update_scope_local_id] = @sync_scope_local_id, 
                [scope_update_peer_key] = @sync_update_peer_key,
                [scope_update_peer_timestamp] = @sync_update_peer_timestamp,
                [local_update_peer_key] = 0,
                [restore_timestamp] = NULL,
                [create_scope_local_id] = @sync_scope_local_id, 
                [scope_create_peer_key] = @sync_create_peer_key, 
                [scope_create_peer_timestamp] =  @sync_create_peer_timestamp, 
                [sync_row_is_tombstone] = @sync_row_is_tombstone                        
            where CustomerId = @CustomerId and PhoneType = @PhoneType   
            and (@sync_check_concurrency = 0 or local_update_peer_timestamp = @sync_row_timestamp)
        else    
            update Sync.CustomerContact_Tracking set
                [update_scope_local_id] = @sync_scope_local_id, 
                [scope_update_peer_key] = @sync_update_peer_key,
                [scope_update_peer_timestamp] = @sync_update_peer_timestamp,
                [local_update_peer_key] = 0,
                [restore_timestamp] = NULL,
                [sync_row_is_tombstone] = @sync_row_is_tombstone                        
            where CustomerId = @CustomerId and PhoneType = @PhoneType 
            and (@sync_check_concurrency = 0 or local_update_peer_timestamp = @sync_row_timestamp)
        set @sync_row_count = @@rowcount
    create procedure Sync.sp_Customer_UpdateMetadata (
            @CustomerId uniqueidentifier,
            @sync_scope_local_id int,
            @sync_row_is_tombstone int,
            @sync_create_peer_key int,
            @sync_create_peer_timestamp bigint,                 
            @sync_update_peer_key int,
            @sync_update_peer_timestamp timestamp,                      
            @sync_row_timestamp timestamp,
            @sync_check_concurrency int,        
            @sync_row_count int out)        
    as  
        declare @was_tombstone int
        select @was_tombstone = sync_row_is_tombstone from Sync.Customer_Tracking 
        where CustomerId = @CustomerId
        
        if (@was_tombstone is not null and @was_tombstone=1 and @sync_row_is_tombstone=0)
            -- tombstone is getting resurrected, update creation version as well
            update Sync.Customer_Tracking set
                [update_scope_local_id] = @sync_scope_local_id, 
                [scope_update_peer_key] = @sync_update_peer_key,
                [scope_update_peer_timestamp] = @sync_update_peer_timestamp,
                [local_update_peer_key] = 0,
                [restore_timestamp] = NULL,
                [create_scope_local_id] = @sync_scope_local_id, 
                [scope_create_peer_key] = @sync_create_peer_key, 
                [scope_create_peer_timestamp] =  @sync_create_peer_timestamp, 
                [sync_row_is_tombstone] = @sync_row_is_tombstone                        
            where CustomerId = @CustomerId          
            and (@sync_check_concurrency = 0 or local_update_peer_timestamp = @sync_row_timestamp)
        else    
            update Sync.Customer_Tracking set
                [update_scope_local_id] = @sync_scope_local_id, 
                [scope_update_peer_key] = @sync_update_peer_key,
                [scope_update_peer_timestamp] = @sync_update_peer_timestamp,
                [local_update_peer_key] = 0,
                [restore_timestamp] = NULL,
                [sync_row_is_tombstone] = @sync_row_is_tombstone                        
            where CustomerId = @CustomerId          
            and (@sync_check_concurrency = 0 or local_update_peer_timestamp = @sync_row_timestamp)
        set @sync_row_count = @@rowcount

Procedimento para SelectRowCommand

create procedure Sync.sp_Customer_SelectRow
        @CustomerId uniqueidentifier,
        @sync_scope_local_id int
as
    select  t.CustomerId, 
            c.CustomerName,
            c.SalesPerson,
            c.CustomerType, 
            t.sync_row_is_tombstone,
            t.local_update_peer_timestamp as sync_row_timestamp, 
            case when (t.update_scope_local_id is null or t.update_scope_local_id <> @sync_scope_local_id) 
                 then case when (t.restore_timestamp is null) then t.local_update_peer_timestamp else t.restore_timestamp end else t.scope_update_peer_timestamp end as sync_update_peer_timestamp,
            case when (t.update_scope_local_id is null or t.update_scope_local_id <> @sync_scope_local_id) 
                 then t.local_update_peer_key else t.scope_update_peer_key end as sync_update_peer_key,
            case when (t.create_scope_local_id is null or t.create_scope_local_id <> @sync_scope_local_id) 
                 then t.local_create_peer_timestamp else t.scope_create_peer_timestamp end as sync_create_peer_timestamp,
            case when (t.create_scope_local_id is null or t.create_scope_local_id <> @sync_scope_local_id) 
                 then t.local_create_peer_key else t.scope_create_peer_key end as sync_create_peer_key
    from Sales.Customer c right join Sync.Customer_Tracking t on c.CustomerId = t.CustomerId    
    where c.CustomerId = @CustomerId 

Procedimento para SelectMetadataForCleanupCommand

    CREATE PROCEDURE Sync.sp_Customer_SelectMetadata     
        @metadata_aging_in_days int,
        @sync_scope_local_id int
    AS
        IF @metadata_aging_in_days = -1
            BEGIN
                SELECT  CustomerId,
                        local_update_peer_timestamp as sync_row_timestamp,  
                        case when (update_scope_local_id is null or update_scope_local_id <> @sync_scope_local_id) 
                            then case when (restore_timestamp is null) then local_update_peer_timestamp else restore_timestamp end else scope_update_peer_timestamp end as sync_update_peer_timestamp,
                        case when (update_scope_local_id is null or update_scope_local_id <> @sync_scope_local_id) 
                            then local_update_peer_key else scope_update_peer_key end as sync_update_peer_key,
                        case when (create_scope_local_id is null or create_scope_local_id <> @sync_scope_local_id) 
                            then local_create_peer_timestamp else scope_create_peer_timestamp end as sync_create_peer_timestamp,
                        case when (create_scope_local_id is null or create_scope_local_id <> @sync_scope_local_id) 
                            then local_create_peer_key else scope_create_peer_key end as sync_create_peer_key
                FROM Sync.Customer_Tracking
                WHERE sync_row_is_tombstone = 1
            END
        
        ELSE
            BEGIN
                SELECT  CustomerId,
                        local_update_peer_timestamp as sync_row_timestamp,  
                        case when (update_scope_local_id is null or update_scope_local_id <> @sync_scope_local_id) 
                            then case when (restore_timestamp is null) then local_update_peer_timestamp else restore_timestamp end else scope_update_peer_timestamp end as sync_update_peer_timestamp,
                        case when (update_scope_local_id is null or update_scope_local_id <> @sync_scope_local_id) 
                            then local_update_peer_key else scope_update_peer_key end as sync_update_peer_key,
                        case when (create_scope_local_id is null or create_scope_local_id <> @sync_scope_local_id) 
                            then local_create_peer_timestamp else scope_create_peer_timestamp end as sync_create_peer_timestamp,
                        case when (create_scope_local_id is null or create_scope_local_id <> @sync_scope_local_id) 
                            then local_create_peer_key else scope_create_peer_key end as sync_create_peer_key
                FROM Sync.Customer_Tracking
                WHERE sync_row_is_tombstone = 1 AND
                DATEDIFF(day, last_change_datetime, GETDATE()) > @metadata_aging_in_days
            END

Conclusão

Este tópico mostrou as etapas do provisionamento de um banco de dados para controle de alterações. Depois de ser provisionado, um banco de dados pode ser sincronizado com outros nós. Para obter mais informações sobre como configurar e executar uma sincronização, consulte os tópicos a seguir: Como configurar e executar a sincronização de colaboração (não SQL Server).

Consulte também

Outros recursos

Sincronizando outros bancos de dados compatíveis com ADO.NET

Como configurar e executar a sincronização de colaboração (não SQL Server)