Compartilhar via


Como configurar e executar a sincronização com o SQL Azure

Este tópico mostra como configurar um banco de dados SQL Azure para sincronização com um banco de dados SQL Server e com um banco de dados SQL Server Compact, e como usar o banco de dados SQL Azure como um banco de dados intermediário para sincronizar dados de um banco de dados local SQL Server para e da Web com um banco de dados cliente do SQL Server Compact. Os exemplos neste tópico destacam as seguintes classes do Sync Framework:

Noções básicas sobre a sincronização do SQL Azure

O armazenamento de seus dados no Banco de dados do SQL Azure permite que você aproveite vários benefícios, como o acesso seguro aos seus dados a partir de qualquer computador que possa se conectar à Internet. Ao usar o Sync Framework para sincronizar dados entre um banco de dados do SQL Server no local dos seus negócios e um banco de dados SQL Azure, você pode disponibilizar parte de ou todos os seus dados para outros usuários, sem precisar fornecer uma conexão ao seu banco de dados local do SQL Server. Após você configurar o banco de dados SQL Azure para sincronização, usuários trabalhando fora do seu firewall de negócios, como vendedores remotos, podem sincronizar dados para um banco de dados cliente, como um banco de dados SQL Server Compact. Alterações feitas nos dados no campo podem ser sincronizadas para o banco de dados SQL Azure e depois para o banco de dados local SQL Server.

O uso da arquitetura de 2 camadas ou de uma arquitetura de N camadas são duas maneiras típicas de estruturar um aplicativo que sincroniza um banco de dados SQL Server com um banco de dados SQL Azure.

  • **Arquitetura de 2 camadas:**Sync Framework executada no computador local e utiliza um objeto SqlSyncProvider para se conectar ao banco de dados SQL Azure, bem como a qualquer outro banco de dados do SQL Server. Este tópico destaca a arquitetura de 2 camadas.

  • Arquitetura de N camadas: um provedor de banco de dados Sync Framework é executado em um serviço hospedado do Windows Azure e se comunica com um provedor proxy executado no computador local. Para obter mais informações, consulte Como implantar o Sync Framework no Windows Azure.

Para obter mais informações sobre a arquitetura de sincronização, consulte Arquitetura e classes para sincronização de bancos de dados.

Sincronizando o SQL Server e o SQL Azure

A primeira etapa para colocar seus dados locais na Web é criar um banco de dados SQL Azure, definir o escopo do que será sincronizado entre os bancos de dados SQL Azure e SQL Server, e provisionar os bancos de dados para que eles sincronizem entre si. Após serem configurados adequadamente para sincronização, os bancos de dados podem ser sincronizados a qualquer momento, usando o mesmo código Sync Framework usado para sincronizar para bancos de dados do SQL Server. As seções a seguir descrevem como provisionar e sincronizar seus bancos de dados.

Provisionando o banco de dados SQL Azure para sincronização

Para que outro banco de dados possa sincronizar com um banco de dados SQL Azure, primeiro é necessário provisionar o banco de dados SQL Azure para sincronização. O provisionamento de um banco de dados cria as tabelas de metadados e o procedimentos armazenados necessários que o Sync Framework requer para realizar a sincronização. No cenário em que um banco de dados do SQL Server já existe e um novo banco de dados do SQL Azure é usado, primeiro você define o escopo de sincronização com base em tabelas do banco de dados do SQL Server e, em seguida, provisiona os bancos de dados do SQL Server e do SQL Azure.

Dica

Em algumas situações, quando houver falha no provisionamento de um banco de dados do SQL Azure, a transação de provisionamento não poderá ser revertida. Nessas situações, DbPartiallyProvisionedException é descartado. Isso significa que, se DbPartiallyProvisionedException for descartado durante o provisionamento de um banco de dados do SQL Azure, você deverá primeiro desprovisionar o escopo com falha ou o modelo antes de tentar provisioná-lo novamente, ou haverá falha no provisionamento.

O exemplo a seguir define uma descrição de escopo com base em duas tabelas de um banco de dados local do SQL Server e a utiliza para provisionar o banco de dados local e um banco de dados do SQL Azure para sincronização. Lembre-se de que, para que este código possa ser executado, você deve criar um banco de dados do SQL Azure e fornecer a cadeia de conexão adequada para Utility.ConnStr_SqlAzure_Server. Para obter mais informações sobre cadeias de conexão, consulte Conexões de banco de dados.

SqlConnection onPremiseConn = new SqlConnection(Utility.ConnStr_SqlSync_Server);
SqlConnection azureConn = new SqlConnection(Utility.ConnStr_SqlAzure_Server);

// First provision the on-premise SQL Server database for synchronization.

// Create a scope named "customers" and add tables to it.
DbSyncScopeDescription customersScopeDesc = new DbSyncScopeDescription("customers");

// Definition for Customer.
DbSyncTableDescription customerDescription =
    SqlSyncDescriptionBuilder.GetDescriptionForTable("Sales.Customer", onPremiseConn);

customersScopeDesc.Tables.Add(customerDescription);

// Definition for CustomerContact, including the list of columns to include.
Collection<string> columnsToInclude = new Collection<string>();
columnsToInclude.Add("CustomerId");
columnsToInclude.Add("PhoneType");
DbSyncTableDescription customerContactDescription =
    SqlSyncDescriptionBuilder.GetDescriptionForTable("Sales.CustomerContact", columnsToInclude, onPremiseConn);

customersScopeDesc.Tables.Add(customerContactDescription);

// Create a provisioning object for "customers" and apply it to the on-premise database.
SqlSyncScopeProvisioning onPremiseConfig = new SqlSyncScopeProvisioning(onPremiseConn, customersScopeDesc);
onPremiseConfig.Apply();

// Provision the SQL Azure database from the on-premise SQL Server database.
SqlSyncScopeProvisioning azureCustomersConfig = new SqlSyncScopeProvisioning(azureConn, customersScopeDesc);
azureCustomersConfig.Apply();
Dim onPremiseConn As New SqlConnection(Utility.ConnStr_SqlSync_Server)
Dim azureConn As New SqlConnection(Utility.ConnStr_SqlAzure_Server)

' First provision the on-premise SQL Server database for synchronization.

' Create a scope named "customers" and add tables to it.
Dim customersScopeDesc As New DbSyncScopeDescription("customers")

' Definition for Customer.
Dim customerDescription As DbSyncTableDescription = SqlSyncDescriptionBuilder.GetDescriptionForTable("Sales.Customer", onPremiseConn)

customersScopeDesc.Tables.Add(customerDescription)

' Definition for CustomerContact, including the list of columns to include.
Dim columnsToInclude As New Collection(Of String)()
columnsToInclude.Add("CustomerId")
columnsToInclude.Add("PhoneType")
Dim customerContactDescription As DbSyncTableDescription = SqlSyncDescriptionBuilder.GetDescriptionForTable("Sales.CustomerContact", columnsToInclude, onPremiseConn)

customersScopeDesc.Tables.Add(customerContactDescription)

' Create a provisioning object for "customers" and apply it to the on-premise database.
Dim onPremiseConfig As New SqlSyncScopeProvisioning(onPremiseConn, customersScopeDesc)
onPremiseConfig.Apply()

' Provision the SQL Azure database from the on-premise SQL Server database.
Dim azureCustomersConfig As New SqlSyncScopeProvisioning(azureConn, customersScopeDesc)
azureCustomersConfig.Apply()

Sincronizando os bancos de dados

Após o provisionamento dos bancos de dados SQL Azure e SQL Server com um escopo em comum, é possível sincronizá-los usando dois objetos SqlSyncProvider e um objeto SyncOrchestrator. Como o SQL Azure é um ambiente compartilhado, ele contém recursos para garantir que nenhum usuário utilize recursos em excesso. Algo preocupante na sincronização são os limites de utilização de recursos, o que também é chamado de limitação; isso significa que uma transação pode ser interrompida pelo Windows Azure quando é muito longa ou se o processo gera carga de CPU ou de E/S em excesso. O Sync Framework trata da limitação de diversas formas:

  • Quando há falha na aplicação de alterações, o Sync Framework por padrão repete a transação mais duas vezes antes de parar a sincronização.

  • Quando há falha na aplicação de alterações, o Sync Framework dispara o evento DbConnectionFailure. O aplicativo de sincronização pode registrar-se para manipular esse evento e pode optar por repetir a transação ou cancelar a sincronização.

  • A propriedade MaximumApplicationTransactionSize pode ser definida para limitar o tamanho de cada transação a um número especificado de quilobytes. Isso pode ajudar a evitar problemas de limitação pois mantém o tamanho da transação dentro da limitação especificada. Uma configuração típica desse valor é de 10 a 50 megabytes. Quanto maior for a largura de banda de sua rede, maior poderá ser esse valor. Valores inferiores a 1 megabyte não são recomendados, pois podem causar um grande impacto no desempenho. Lembre-se de que o valor deve ser maior do que a maior linha possível no seu escopo de sincronização, ou a sincronização falhará. Quando esse valor é definido, o Sync Framework toma o cuidado de dividir os lotes de alterações para que cada transação seja mantida dentro do limite de tamanho máximo especificado.

Outra preocupação ao trabalhar com o SQL Azure é a possibilidade de que um comando SQL demore mais do que o esperado para ser concluído, retendo seu aplicativo. Nesse caso, seria melhor interromper a sincronização e repetir o procedimento em outra ocasião. Ou, como o tempo limite padrão de um comando é o tempo limite ADO.NET de 30 segundos, talvez você queira especificar um tempo limite maior se imagina que um de seus comandos leve mais de 30 segundos para ser executado. Para alterar o tempo limite padrão, defina a propriedade SqlSyncProvider..::..CommandTimeout com um número especificado de segundos de espera para que um comando enviado para SQL Azure seja cancelado, ou defina o valor da propriedade como 0 para indicar que comandos não têm tempo limite.

O exemplo a seguir define um tempo limite de 60 segundos para comandos SQL Azure, define um tempo máximo de transação para o aplicativo de alterações de 50 megabytes, registra um manipulador para o evento DbConnectionFailure. Estas configurações são opcionais e não são necessárias para a sincronização. O exemplo sincroniza os bancos de dados SQL Azure e SQL Server. Após a execução deste código, os dois bancos de dados contêm os mesmos dados para o escopo especificado.

SampleSyncOrchestrator syncOrchestrator;
SyncOperationStatistics syncStats;

// Set the command timeout and maximum transaction size for the SQL Azure provider.
SqlSyncProvider azureProvider = new SqlSyncProvider("customers", azureConn); 
azureProvider.CommandTimeout = 60; // 60 second timeout
azureProvider.MaximumApplicationTransactionSize = 50 * 1024; // 50 megabytes
azureProvider.DbConnectionFailure += new EventHandler<DbConnectionFailureEventArgs>(HandleDbConnectionFailure);

syncOrchestrator = new SampleSyncOrchestrator(
    new SqlSyncProvider("customers", onPremiseConn),
    azureProvider
    );
syncStats = syncOrchestrator.Synchronize();
syncOrchestrator.DisplayStats(syncStats, "initial");
Dim syncOrchestrator As SampleSyncOrchestrator
Dim syncStats As SyncOperationStatistics

' Set the command timeout and maximum transaction size for the SQL Azure provider.
Dim azureProvider As New SqlSyncProvider("customers", azureConn)
azureProvider.CommandTimeout = 60 ' 60 second timeout
azureProvider.MaximumApplicationTransactionSize = 50 * 1024 ' 50 megabytes
AddHandler azureProvider.DbConnectionFailure, AddressOf HandleDbConnectionFailure

syncOrchestrator = New SampleSyncOrchestrator(New SqlSyncProvider("customers", onPremiseConn), azureProvider)
syncStats = syncOrchestrator.Synchronize()
syncOrchestrator.DisplayStats(syncStats, "initial")

O exemplo a seguir mostra o manipulador de eventos DbConnectionFailure. Esse manipulador de eventos verifica o número de tentativas de repetição e substitui o padrão para repetir a aplicação de alterações 10 vezes antes de parar a sincronização.

       static void HandleDbConnectionFailure(object sender, DbConnectionFailureEventArgs e)
       {
            // Override the default to retry 10 times before fail.
           if (e.ApplyTransactionRetry < 10)
           {
               e.Action = DbConnectionFailureAction.Retry;
           }
           else
           {
               e.Action = DbConnectionFailureAction.AbortSync;
           }
       }
Private Shared Sub HandleDbConnectionFailure(ByVal sender As Object, ByVal e As DbConnectionFailureEventArgs)
    ' Override the default to retry 10 times before fail.
    If e.ApplyTransactionRetry < 10 Then
        e.Action = DbConnectionFailureAction.Retry
    Else
        e.Action = DbConnectionFailureAction.AbortSync
    End If
End Sub

Sincronizando o SQL Azure e o SQL Server Compact

Agora que seus dados foram sincronizados para um banco de dados SQL Azure, ele está disponível para sincronização com clientes, como um banco de dados SQL Server Compact. Muitas vezes, os clientes não precisam de todos os dados. Neste cenário, escopos filtrados podem ser usados para garantir que cada cliente obtenha apenas o subconjunto de dados necessário. A criação de um modelo de filtro baseado em parâmetros no banco de dados SQL Azure permite que clientes especifiquem valores de parâmetro e criem escopos filtrados conforme necessário. Após a definição e o provisionamento de um escopo filtrado, os bancos de dados SQL Azure e SQL Server Compact podem ser sincronizados a qualquer momento, usando um código semelhante àquele usado para sincronizar bancos de dados SQL Server e SQL Server Compact.

Provisionando um modelo de filtro baseado em parâmetros

Para provisionar a sincronização filtrada de banco de dados SQL Azure, defina primeiro um modelo de escopo filtrado. O modelo de escopo filtrado descreve o conjunto de tabelas no escopo filtrado, as colunas a serem usadas para filtragem, e a cláusula de filtro que define a relação entre as colunas e os parâmetros do filtro. Como o banco de dados já contém um escopo de sincronização, especifique que o Sync Framework deve ignorar a criação de um conjunto padrão de procedimentos armazenados, em vez de criar apenas aqueles necessários para um escopo adicional. Isso é obtido especificando Skip para o método SetCreateProceduresDefault e Create para o método SetCreateProceduresForAdditionalScopeDefault. Além disso, lembre-se de que, quando uma tabela já faz parte de um escopo de sincronização, já tem uma tabela de rastreamento criada para ela. Quando um novo escopo filtrado contém a mesma tabela, o Sync Framework automaticamente adiciona a coluna de filtro à tabela de rastreamento. Para conseguir isso, a coluna de filtro deve ser definida para permitir valores nulos ou deve ter um valor padrão definido para a coluna.

Para obter mais informações, consulte Como filtrar dados para sincronização de bancos de dados (SQL Server).

O exemplo a seguir mostra como criar um modelo de escopo para filtragem baseada em parâmetros. O modelo de escopo contém duas tabelas, sendo que uma delas é filtrada por sua coluna CustomerType.

DbSyncScopeDescription customerTypeTemplateDesc = new DbSyncScopeDescription("customertype_template");

// Set a friendly description of the template.
customerTypeTemplateDesc.UserDescription = "Template for Customer and CustomerContact tables. Customer data is filtered by CustomerType parameter.";

// Add tables to the scope.
DbSyncTableDescription azureCustomerDescription =
    SqlSyncDescriptionBuilder.GetDescriptionForTable("Sales.Customer", azureConn);
customerTypeTemplateDesc.Tables.Add(customerDescription);
DbSyncTableDescription azureCustomerContactDescription =
    SqlSyncDescriptionBuilder.GetDescriptionForTable("Sales.CustomerContact", azureConn);
customerTypeTemplateDesc.Tables.Add(customerContactDescription);

// Create a provisioning object for "customertype_template" that can be used to create a template
// from which filtered synchronization scopes can be created.
SqlSyncScopeProvisioning customerTypeTemplate = new SqlSyncScopeProvisioning(azureConn, customerTypeTemplateDesc, SqlSyncScopeProvisioningType.Template);

// Specify the column in the Customer table to use for filtering data, 
// and the filtering clause to use against the tracking table.
// "[side]" is an alias for the tracking table.
// The CustomerType column that defines the filter is set up as a parameter in this template.
// An actual customer type will be specified later, when the synchronization scope is created.
customerTypeTemplate.Tables["Sales.Customer"].AddFilterColumn("CustomerType");
customerTypeTemplate.Tables["Sales.Customer"].FilterClause = "[side].[CustomerType] = @customertype";
SqlParameter param = new SqlParameter("@customertype", SqlDbType.NVarChar, 100);
customerTypeTemplate.Tables["Sales.Customer"].FilterParameters.Add(param);

// Because this new scope adds a filtering clause and the existing scope in the database does not
// include filtering, specify that creating stored procedures that already exist must be skipped 
// and that new stored procedures be created for the additional scope.
customerTypeTemplate.SetCreateProceduresDefault(DbSyncCreationOption.Skip);
customerTypeTemplate.SetCreateProceduresForAdditionalScopeDefault(DbSyncCreationOption.Create);

// Create the "customertype_template" template in the database.
customerTypeTemplate.Apply();
Dim customerTypeTemplateDesc As New DbSyncScopeDescription("customertype_template")

' Set a friendly description of the template.
customerTypeTemplateDesc.UserDescription = "Template for Customer and CustomerContact tables. Customer data is filtered by CustomerType parameter."

' Add tables to the scope.
Dim azureCustomerDescription As DbSyncTableDescription = SqlSyncDescriptionBuilder.GetDescriptionForTable("Sales.Customer", azureConn)
customerTypeTemplateDesc.Tables.Add(customerDescription)
Dim azureCustomerContactDescription As DbSyncTableDescription = SqlSyncDescriptionBuilder.GetDescriptionForTable("Sales.CustomerContact", azureConn)
customerTypeTemplateDesc.Tables.Add(customerContactDescription)

' Create a provisioning object for "customertype_template" that can be used to create a template
' from which filtered synchronization scopes can be created.
Dim customerTypeTemplate As New SqlSyncScopeProvisioning(azureConn, customerTypeTemplateDesc, SqlSyncScopeProvisioningType.Template)

' Specify the column in the Customer table to use for filtering data, 
' and the filtering clause to use against the tracking table.
' "[side]" is an alias for the tracking table.
' The CustomerType column that defines the filter is set up as a parameter in this template.
' An actual customer type will be specified later, when the synchronization scope is created.
customerTypeTemplate.Tables("Sales.Customer").AddFilterColumn("CustomerType")
customerTypeTemplate.Tables("Sales.Customer").FilterClause = "[side].[CustomerType] = @customertype"
Dim param As New SqlParameter("@customertype", SqlDbType.NVarChar, 100)
customerTypeTemplate.Tables("Sales.Customer").FilterParameters.Add(param)

' Because this new scope adds a filtering clause and the existing scope in the database does not
' include filtering, specify that creating stored procedures that already exist must be skipped 
' and that new stored procedures be created for the additional scope.
customerTypeTemplate.SetCreateProceduresDefault(DbSyncCreationOption.Skip)
customerTypeTemplate.SetCreateProceduresForAdditionalScopeDefault(DbSyncCreationOption.Create)

' Create the "customertype_template" template in the database.
customerTypeTemplate.Apply()

Provisionando um escopo filtrado

Agora que um modelo de escopo filtrado foi definido no banco de dados SQL Azure, os escopos filtrados podem ser criados a partir dele e usados para provisionar outros bancos de dados, como o banco de dados cliente SQL Server Compact. Para criar um escopo filtrado, atribua um nome ao novo escopo e defina o valor de todos os parâmetros de filtro. O escopo filtrado pode ser usado para provisionar o banco de dados do SQL Azure e outros bancos de dados.

O exemplo a seguir mostra como definir um escopo filtrado que inclua somente itens da tabela Sales.Customer que tenham um valor de CustomerType igual a Retail. O escopo filtrado é usado para provisionar o banco de dados SQL Azure e um banco de dados cliente do SQL Server Compact para sincronização filtrada.

SqlSyncScopeProvisioning azureRetailCustomersScope = new SqlSyncScopeProvisioning(azureConn);
azureRetailCustomersScope.PopulateFromTemplate("RetailCustomers", "customertype_template");
azureRetailCustomersScope.Tables["Sales.Customer"].FilterParameters["@customertype"].Value = "Retail";
azureRetailCustomersScope.UserDescription = "Customer data includes only retail customers.";
azureRetailCustomersScope.Apply();

// Create a SQL Server Compact database and provision it based on the retail customer scope
// retrieved from the SQL Azure database.
SqlCeConnection clientSqlCeConn = new SqlCeConnection(Utility.ConnStr_SqlCeSync1);
Utility.DeleteAndRecreateCompactDatabase(Utility.ConnStr_SqlCeSync1, true);

DbSyncScopeDescription azureRetailCustomersDesc = SqlSyncDescriptionBuilder.GetDescriptionForScope("RetailCustomers", azureConn); 
SqlCeSyncScopeProvisioning clientSqlCeConfig = new SqlCeSyncScopeProvisioning(clientSqlCeConn, azureRetailCustomersDesc);
clientSqlCeConfig.Apply();
Dim azureRetailCustomersScope As New SqlSyncScopeProvisioning(azureConn)
azureRetailCustomersScope.PopulateFromTemplate("RetailCustomers", "customertype_template")
azureRetailCustomersScope.Tables("Sales.Customer").FilterParameters("@customertype").Value = "Retail"
azureRetailCustomersScope.UserDescription = "Customer data includes only retail customers."
azureRetailCustomersScope.Apply()

' Create a SQL Server Compact database and provision it based on the retail customer scope
' retrieved from the SQL Azure database.
Dim clientSqlCeConn As New SqlCeConnection(Utility.ConnStr_SqlCeSync1)
Utility.DeleteAndRecreateCompactDatabase(Utility.ConnStr_SqlCeSync1, True)

Dim azureRetailCustomersDesc As DbSyncScopeDescription = SqlSyncDescriptionBuilder.GetDescriptionForScope("RetailCustomers", azureConn)
Dim clientSqlCeConfig As New SqlCeSyncScopeProvisioning(clientSqlCeConn, azureRetailCustomersDesc)
clientSqlCeConfig.Apply()

Sincronizando os bancos de dados

Após o provisionamento dos bancos de dados SQL Azure e SQL Server Compact com um escopo filtrado em comum, é possível sincronizá-los usando um objeto SqlSyncProvider, um objeto SqlCeSyncProvider e um objeto SyncOrchestrator. O exemplo a seguir mostra como fazer isso.

syncOrchestrator = new SampleSyncOrchestrator(
    new SqlCeSyncProvider("RetailCustomers", clientSqlCeConn),
    new SqlSyncProvider("RetailCustomers", azureConn)
);
syncStats = syncOrchestrator.Synchronize();
syncOrchestrator.DisplayStats(syncStats, "subsequent");
syncOrchestrator = New SampleSyncOrchestrator(New SqlCeSyncProvider("RetailCustomers", clientSqlCeConn), New SqlSyncProvider("RetailCustomers", azureConn))
syncStats = syncOrchestrator.Synchronize()
syncOrchestrator.DisplayStats(syncStats, "subsequent")

Exemplo completo

O exemplo a seguir inclui os exemplos de código descritos anteriormente e o código adicional para executar a sincronização. O exemplo requer a classe Utility que está disponível em Classe de utilitário para tópicos de instruções do provedor de banco de dados.

using System;
using System.Collections.ObjectModel;
using System.IO;
using System.Text;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlServerCe;
using Microsoft.Synchronization;
using Microsoft.Synchronization.Data;
using Microsoft.Synchronization.Data.SqlServer;
using Microsoft.Synchronization.Data.SqlServerCe;

namespace Microsoft.Samples.Synchronization
{
    class Program
    {
        static void Main(string[] args)
        {
            // This example shows how to set up a system where a SQL Azure database is used as a central
            // store for synchronization between a SQL Server database and a SQL Server Compact databse.
            // This is a typical scenario where a SQL Server database that is used on your business premises 
            // synchronizes with a SQL Azure database to bring your data to the cloud. The SQL Azure database 
            // is synchronized with SQL Server Compact databases used by remote workers, such as salespeople.

            // Create the connections over which provisioning and synchronization
            // are performed. The Utility class handles all functionality that is not
            // directly related to synchronization, such as holding connection 
            // string information and making changes to the server database.
            SqlConnection onPremiseConn = new SqlConnection(Utility.ConnStr_SqlSync_Server);
            SqlConnection azureConn = new SqlConnection(Utility.ConnStr_SqlAzure_Server);

            // First provision the on-premise SQL Server database for synchronization.

            // Create a scope named "customers" and add tables to it.
            DbSyncScopeDescription customersScopeDesc = new DbSyncScopeDescription("customers");

            // Definition for Customer.
            DbSyncTableDescription customerDescription =
                SqlSyncDescriptionBuilder.GetDescriptionForTable("Sales.Customer", onPremiseConn);

            customersScopeDesc.Tables.Add(customerDescription);

            // Definition for CustomerContact, including the list of columns to include.
            Collection<string> columnsToInclude = new Collection<string>();
            columnsToInclude.Add("CustomerId");
            columnsToInclude.Add("PhoneType");
            DbSyncTableDescription customerContactDescription =
                SqlSyncDescriptionBuilder.GetDescriptionForTable("Sales.CustomerContact", columnsToInclude, onPremiseConn);

            customersScopeDesc.Tables.Add(customerContactDescription);

            // Create a provisioning object for "customers" and apply it to the on-premise database.
            SqlSyncScopeProvisioning onPremiseConfig = new SqlSyncScopeProvisioning(onPremiseConn, customersScopeDesc);
            onPremiseConfig.Apply();

            // Provision the SQL Azure database from the on-premise SQL Server database.
            SqlSyncScopeProvisioning azureCustomersConfig = new SqlSyncScopeProvisioning(azureConn, customersScopeDesc);
            azureCustomersConfig.Apply();

            // Perform an initial synchronization between the on-premise SQL Server database and the SQL Azure database.
            SampleSyncOrchestrator syncOrchestrator;
            SyncOperationStatistics syncStats;

            // Set the command timeout and maximum transaction size for the SQL Azure provider.
            SqlSyncProvider azureProvider = new SqlSyncProvider("customers", azureConn); 
            azureProvider.CommandTimeout = 60; // 60 second timeout
            azureProvider.MaximumApplicationTransactionSize = 50 * 1024; // 50 megabytes
            azureProvider.DbConnectionFailure += new EventHandler<DbConnectionFailureEventArgs>(HandleDbConnectionFailure);

            syncOrchestrator = new SampleSyncOrchestrator(
                new SqlSyncProvider("customers", onPremiseConn),
                azureProvider
                );
            syncStats = syncOrchestrator.Synchronize();
            syncOrchestrator.DisplayStats(syncStats, "initial");

            // Provision the SQL Azure database for filtered synchronization.

            // Create a scope named "customertype_template", and add two tables to the scope.
            DbSyncScopeDescription customerTypeTemplateDesc = new DbSyncScopeDescription("customertype_template");

            // Set a friendly description of the template.
            customerTypeTemplateDesc.UserDescription = "Template for Customer and CustomerContact tables. Customer data is filtered by CustomerType parameter.";

            // Add tables to the scope.
            DbSyncTableDescription azureCustomerDescription =
                SqlSyncDescriptionBuilder.GetDescriptionForTable("Sales.Customer", azureConn);
            customerTypeTemplateDesc.Tables.Add(customerDescription);
            DbSyncTableDescription azureCustomerContactDescription =
                SqlSyncDescriptionBuilder.GetDescriptionForTable("Sales.CustomerContact", azureConn);
            customerTypeTemplateDesc.Tables.Add(customerContactDescription);

            // Create a provisioning object for "customertype_template" that can be used to create a template
            // from which filtered synchronization scopes can be created.
            SqlSyncScopeProvisioning customerTypeTemplate = new SqlSyncScopeProvisioning(azureConn, customerTypeTemplateDesc, SqlSyncScopeProvisioningType.Template);

            // Specify the column in the Customer table to use for filtering data, 
            // and the filtering clause to use against the tracking table.
            // "[side]" is an alias for the tracking table.
            // The CustomerType column that defines the filter is set up as a parameter in this template.
            // An actual customer type will be specified later, when the synchronization scope is created.
            customerTypeTemplate.Tables["Sales.Customer"].AddFilterColumn("CustomerType");
            customerTypeTemplate.Tables["Sales.Customer"].FilterClause = "[side].[CustomerType] = @customertype";
            SqlParameter param = new SqlParameter("@customertype", SqlDbType.NVarChar, 100);
            customerTypeTemplate.Tables["Sales.Customer"].FilterParameters.Add(param);

            // Because this new scope adds a filtering clause and the existing scope in the database does not
            // include filtering, specify that creating stored procedures that already exist must be skipped 
            // and that new stored procedures be created for the additional scope.
            customerTypeTemplate.SetCreateProceduresDefault(DbSyncCreationOption.Skip);
            customerTypeTemplate.SetCreateProceduresForAdditionalScopeDefault(DbSyncCreationOption.Create);

            // Create the "customertype_template" template in the database.
            customerTypeTemplate.Apply();

            // Create a synchronization scope for retail customers.
            SqlSyncScopeProvisioning azureRetailCustomersScope = new SqlSyncScopeProvisioning(azureConn);
            azureRetailCustomersScope.PopulateFromTemplate("RetailCustomers", "customertype_template");
            azureRetailCustomersScope.Tables["Sales.Customer"].FilterParameters["@customertype"].Value = "Retail";
            azureRetailCustomersScope.UserDescription = "Customer data includes only retail customers.";
            azureRetailCustomersScope.Apply();

            // Create a SQL Server Compact database and provision it based on the retail customer scope
            // retrieved from the SQL Azure database.
            SqlCeConnection clientSqlCeConn = new SqlCeConnection(Utility.ConnStr_SqlCeSync1);
            Utility.DeleteAndRecreateCompactDatabase(Utility.ConnStr_SqlCeSync1, true);

            DbSyncScopeDescription azureRetailCustomersDesc = SqlSyncDescriptionBuilder.GetDescriptionForScope("RetailCustomers", azureConn); 
            SqlCeSyncScopeProvisioning clientSqlCeConfig = new SqlCeSyncScopeProvisioning(clientSqlCeConn, azureRetailCustomersDesc);
            clientSqlCeConfig.Apply();

            // Now synchronize between the SQL Azure database and the SQL Server Compact database.
            syncOrchestrator = new SampleSyncOrchestrator(
                new SqlCeSyncProvider("RetailCustomers", clientSqlCeConn),
                new SqlSyncProvider("RetailCustomers", azureConn)
            );
            syncStats = syncOrchestrator.Synchronize();
            syncOrchestrator.DisplayStats(syncStats, "subsequent");

            // Shut down.
            onPremiseConn.Close();
            onPremiseConn.Dispose();
            azureConn.Close();
            azureConn.Dispose();
            clientSqlCeConn.Close();
            clientSqlCeConn.Dispose();

            Console.Write("\nPress any key to exit.");
            Console.Read();
        }

        static void HandleDbConnectionFailure(object sender, DbConnectionFailureEventArgs e)
        {
            // Override the default to retry 10 times before fail.
            if (e.ApplyTransactionRetry < 10)
            {
                e.Action = DbConnectionFailureAction.Retry;
            }
            else
            {
                e.Action = DbConnectionFailureAction.AbortSync;
            }
        }
    }

    public class SampleSyncOrchestrator : SyncOrchestrator
    {
        public SampleSyncOrchestrator(RelationalSyncProvider localProvider, RelationalSyncProvider remoteProvider)
        {

            this.LocalProvider = localProvider;
            this.RemoteProvider = remoteProvider;
            this.Direction = SyncDirectionOrder.UploadAndDownload;
        }

        public void DisplayStats(SyncOperationStatistics syncStatistics, string syncType)
        {
            Console.WriteLine(String.Empty);
            if (syncType == "initial")
            {
                Console.WriteLine("****** Initial Synchronization ******");
            }
            else if (syncType == "subsequent")
            {
                Console.WriteLine("***** Subsequent Synchronization ****");
            }

            Console.WriteLine("Start Time: " + syncStatistics.SyncStartTime);
            Console.WriteLine("Total Changes Uploaded: " + syncStatistics.UploadChangesTotal);
            Console.WriteLine("Total Changes Downloaded: " + syncStatistics.DownloadChangesTotal);
            Console.WriteLine("Complete Time: " + syncStatistics.SyncEndTime);
            Console.WriteLine(String.Empty);
        }
    }
}
Imports System.Collections.ObjectModel
Imports System.IO
Imports System.Text
Imports System.Data
Imports System.Data.SqlClient
Imports System.Data.SqlServerCe
Imports Microsoft.Synchronization
Imports Microsoft.Synchronization.Data
Imports Microsoft.Synchronization.Data.SqlServer
Imports Microsoft.Synchronization.Data.SqlServerCe

Namespace Microsoft.Samples.Synchronization
    Class Program
        Shared Sub Main(ByVal args As String())
            ' This example shows how to set up a system where a SQL Azure database is used as a central
            ' store for synchronization between a SQL Server database and a SQL Server Compact databse.
            ' This is a typical scenario where a SQL Server database that is used on your business premises 
            ' synchronizes with a SQL Azure database to bring your data to the cloud. The SQL Azure database 
            ' is synchronized with SQL Server Compact databases used by remote workers, such as salespeople.

            ' Create the connections over which provisioning and synchronization
            ' are performed. The Utility class handles all functionality that is not
            ' directly related to synchronization, such as holding connection 
            ' string information and making changes to the server database.
            Dim onPremiseConn As New SqlConnection(Utility.ConnStr_SqlSync_Server)
            Dim azureConn As New SqlConnection(Utility.ConnStr_SqlAzure_Server)

            ' First provision the on-premise SQL Server database for synchronization.

            ' Create a scope named "customers" and add tables to it.
            Dim customersScopeDesc As New DbSyncScopeDescription("customers")

            ' Definition for Customer.
            Dim customerDescription As DbSyncTableDescription = SqlSyncDescriptionBuilder.GetDescriptionForTable("Sales.Customer", onPremiseConn)

            customersScopeDesc.Tables.Add(customerDescription)

            ' Definition for CustomerContact, including the list of columns to include.
            Dim columnsToInclude As New Collection(Of String)()
            columnsToInclude.Add("CustomerId")
            columnsToInclude.Add("PhoneType")
            Dim customerContactDescription As DbSyncTableDescription = SqlSyncDescriptionBuilder.GetDescriptionForTable("Sales.CustomerContact", columnsToInclude, onPremiseConn)

            customersScopeDesc.Tables.Add(customerContactDescription)

            ' Create a provisioning object for "customers" and apply it to the on-premise database.
            Dim onPremiseConfig As New SqlSyncScopeProvisioning(onPremiseConn, customersScopeDesc)
            onPremiseConfig.Apply()

            ' Provision the SQL Azure database from the on-premise SQL Server database.
            Dim azureCustomersConfig As New SqlSyncScopeProvisioning(azureConn, customersScopeDesc)
            azureCustomersConfig.Apply()

            ' Perform an initial synchronization between the on-premise SQL Server database and the SQL Azure database.
            Dim syncOrchestrator As SampleSyncOrchestrator
            Dim syncStats As SyncOperationStatistics

            ' Set the command timeout and maximum transaction size for the SQL Azure provider.
            Dim azureProvider As New SqlSyncProvider("customers", azureConn)
            azureProvider.CommandTimeout = 60 ' 60 second timeout
            azureProvider.MaximumApplicationTransactionSize = 50 * 1024 ' 50 megabytes
            AddHandler azureProvider.DbConnectionFailure, AddressOf HandleDbConnectionFailure

            syncOrchestrator = New SampleSyncOrchestrator(New SqlSyncProvider("customers", onPremiseConn), azureProvider)
            syncStats = syncOrchestrator.Synchronize()
            syncOrchestrator.DisplayStats(syncStats, "initial")

            ' Provision the SQL Azure database for filtered synchronization.

            ' Create a scope named "customertype_template", and add two tables to the scope.
            Dim customerTypeTemplateDesc As New DbSyncScopeDescription("customertype_template")

            ' Set a friendly description of the template.
            customerTypeTemplateDesc.UserDescription = "Template for Customer and CustomerContact tables. Customer data is filtered by CustomerType parameter."

            ' Add tables to the scope.
            Dim azureCustomerDescription As DbSyncTableDescription = SqlSyncDescriptionBuilder.GetDescriptionForTable("Sales.Customer", azureConn)
            customerTypeTemplateDesc.Tables.Add(customerDescription)
            Dim azureCustomerContactDescription As DbSyncTableDescription = SqlSyncDescriptionBuilder.GetDescriptionForTable("Sales.CustomerContact", azureConn)
            customerTypeTemplateDesc.Tables.Add(customerContactDescription)

            ' Create a provisioning object for "customertype_template" that can be used to create a template
            ' from which filtered synchronization scopes can be created.
            Dim customerTypeTemplate As New SqlSyncScopeProvisioning(azureConn, customerTypeTemplateDesc, SqlSyncScopeProvisioningType.Template)

            ' Specify the column in the Customer table to use for filtering data, 
            ' and the filtering clause to use against the tracking table.
            ' "[side]" is an alias for the tracking table.
            ' The CustomerType column that defines the filter is set up as a parameter in this template.
            ' An actual customer type will be specified later, when the synchronization scope is created.
            customerTypeTemplate.Tables("Sales.Customer").AddFilterColumn("CustomerType")
            customerTypeTemplate.Tables("Sales.Customer").FilterClause = "[side].[CustomerType] = @customertype"
            Dim param As New SqlParameter("@customertype", SqlDbType.NVarChar, 100)
            customerTypeTemplate.Tables("Sales.Customer").FilterParameters.Add(param)

            ' Because this new scope adds a filtering clause and the existing scope in the database does not
            ' include filtering, specify that creating stored procedures that already exist must be skipped 
            ' and that new stored procedures be created for the additional scope.
            customerTypeTemplate.SetCreateProceduresDefault(DbSyncCreationOption.Skip)
            customerTypeTemplate.SetCreateProceduresForAdditionalScopeDefault(DbSyncCreationOption.Create)

            ' Create the "customertype_template" template in the database.
            customerTypeTemplate.Apply()

            ' Create a synchronization scope for retail customers.
            Dim azureRetailCustomersScope As New SqlSyncScopeProvisioning(azureConn)
            azureRetailCustomersScope.PopulateFromTemplate("RetailCustomers", "customertype_template")
            azureRetailCustomersScope.Tables("Sales.Customer").FilterParameters("@customertype").Value = "Retail"
            azureRetailCustomersScope.UserDescription = "Customer data includes only retail customers."
            azureRetailCustomersScope.Apply()

            ' Create a SQL Server Compact database and provision it based on the retail customer scope
            ' retrieved from the SQL Azure database.
            Dim clientSqlCeConn As New SqlCeConnection(Utility.ConnStr_SqlCeSync1)
            Utility.DeleteAndRecreateCompactDatabase(Utility.ConnStr_SqlCeSync1, True)

            Dim azureRetailCustomersDesc As DbSyncScopeDescription = SqlSyncDescriptionBuilder.GetDescriptionForScope("RetailCustomers", azureConn)
            Dim clientSqlCeConfig As New SqlCeSyncScopeProvisioning(clientSqlCeConn, azureRetailCustomersDesc)
            clientSqlCeConfig.Apply()

            ' Now synchronize between the SQL Azure database and the SQL Server Compact database.
            syncOrchestrator = New SampleSyncOrchestrator(New SqlCeSyncProvider("RetailCustomers", clientSqlCeConn), New SqlSyncProvider("RetailCustomers", azureConn))
            syncStats = syncOrchestrator.Synchronize()
            syncOrchestrator.DisplayStats(syncStats, "subsequent")

            ' Shut down.
            onPremiseConn.Close()
            onPremiseConn.Dispose()
            azureConn.Close()
            azureConn.Dispose()
            clientSqlCeConn.Close()
            clientSqlCeConn.Dispose()

            Console.Write(vbLf & "Press any key to exit.")
            Console.Read()
        End Sub

        Private Shared Sub HandleDbConnectionFailure(ByVal sender As Object, ByVal e As DbConnectionFailureEventArgs)
            ' Override the default to retry 10 times before fail.
            If e.ApplyTransactionRetry < 10 Then
                e.Action = DbConnectionFailureAction.Retry
            Else
                e.Action = DbConnectionFailureAction.AbortSync
            End If
        End Sub
    End Class

    Public Class SampleSyncOrchestrator
        Inherits SyncOrchestrator
        Public Sub New(ByVal localProvider As RelationalSyncProvider, ByVal remoteProvider As RelationalSyncProvider)

            Me.LocalProvider = localProvider
            Me.RemoteProvider = remoteProvider
            Me.Direction = SyncDirectionOrder.UploadAndDownload
        End Sub

        Public Sub DisplayStats(ByVal syncStatistics As SyncOperationStatistics, ByVal syncType As String)
            Console.WriteLine([String].Empty)
            If syncType = "initial" Then
                Console.WriteLine("****** Initial Synchronization ******")
            ElseIf syncType = "subsequent" Then
                Console.WriteLine("***** Subsequent Synchronization ****")
            End If

            Console.WriteLine("Start Time: " & Convert.ToString(syncStatistics.SyncStartTime))
            Console.WriteLine("Total Changes Uploaded: " & Convert.ToString(syncStatistics.UploadChangesTotal))
            Console.WriteLine("Total Changes Downloaded: " & Convert.ToString(syncStatistics.DownloadChangesTotal))
            Console.WriteLine("Complete Time: " & Convert.ToString(syncStatistics.SyncEndTime))
            Console.WriteLine([String].Empty)
        End Sub
    End Class
End Namespace

Consulte também

Outros recursos

Sincronizando o SQL Server e o SQL Server Compact