Как настроить и выполнить синхронизацию с SQL Azure

В этом разделе описывается конфигурация базы данных SQL Azure для синхронизации с базой данных SQL Server и базой данных SQL Server Compact, а также использование базы данных SQL Azure в качестве промежуточной базы данных для синхронизации данных из локальной базы данных SQL Server с Интернетом и с клиентской базой данных SQL Server Compact. В примерах в этом разделе особое внимание уделено следующим классам Sync Framework.

Основные сведения о синхронизации SQL Azure

Сохранение данных в База данных SQL Azure предоставляет многочисленные преимущества, такие как безопасный доступ к данным с любого компьютера с доступом к Интернету. Использование Sync Framework для синхронизации данных базы данных SQL Server внутри компании и базы данных SQL Azure позволяет обеспечить доступность данных целиком или частично для других пользователей без обеспечения соединения с локальной базой данных SQL Server. После настройки базы данных SQL Azure для синхронизации пользователи, не защищенные корпоративным брандмауэром, например продавцы, работающие удаленно, могут синхронизировать данные с клиентской базой данных, такой как база данных SQL Server Compact. Изменения, вносимые удаленными сотрудниками, в процессе синхронизации фиксируются в базе данных SQL Azure и в итоге заносятся в базу данных SQL Server.

Обычно приложение, синхронизирующее базу данных SQL Server с базой данных SQL Azure, структурируется с использованием двухуровневой или многоуровневой архитектуры.

  • Двухуровневая архитектура: Sync Framework запускается на локальном компьютере и использует объект SqlSyncProvider для соединения с базой данных SQL Azure аналогично соединению с любой другой базой данных SQL Server. Этот раздел ориентирован на использование многоуровневой архитектуры.

  • Многоуровневая архитектура: поставщик базы данных Sync Framework запускается в службе, размещенной в Windows Azure, и взаимодействует с поставщиком прокси-сервера, запущенном на локальном компьютере. Дополнительные сведения см. в разделе Как выполнить развертывание платформы Sync Framework в Windows Azure.

Дополнительные сведения об архитектуре синхронизации см. в разделе Архитектура и классы для синхронизации базы данных.

Синхронизация SQL Server и SQL Azure

Для размещения локальных данных в Интернете сначала необходимо создать базу данных SQL Azure, определить область синхронизации для баз данных SQL Azure и SQL Server и провизионировать базы данных для синхронизации между собой. После завершения необходимой настройки баз данных для синхронизации их синхронизацию можно выполнить в любой момент с использованием того же кода Sync Framework, который использовался для синхронизации баз данных SQL Server. В следующих разделах описывается провизионирование и синхронизация используемых баз данных.

Провизионирование базы данных SQL Azure для синхронизации

До того как другую базу данных можно будет синхронизировать с базой данных SQL Azure, базу данных SQL Azure необходимо подготовить к синхронизации. При провизионировании базы данных создаются необходимые таблицы метаданных и хранимые процедуры, для которых Sync Framework требует выполнения синхронизации. В случае, когда база данных SQL Server уже существует и используется новая база данных SQL Azure, сначала определяется область синхронизации на основе таблиц из базы данных SQL Server, а затем выполняется провизионирование баз данных SQL Server и SQL Azure.

Примечание

В ряде случаев при возникновении ошибки провизионирования базы данных SQL Azure откат транзакции провизионирования невозможен. В таких случаях вызывается исключение DbPartiallyProvisionedException. Это означает, что если возникло исключение DbPartiallyProvisionedException в процессе провизионирования базы данных SQL Azure, то перед началом повторного провизионирования нужно сначала отменить провизионирование области или шаблона, в котором возникла ошибка. В противном случае при выполнении повторной попытки провизионирования снова произойдет ошибка.

В следующем примере определяется описание области на основе двух таблиц из локальной базы данных SQL Server, которое используется для провизионирования локальной базы данных и базы данных SQL Azure для синхронизации. Учтите, что до выполнения этого кода необходимо создать базу данных SQL Azure и указать правильную строку соединения для Utility.ConnStr_SqlAzure_Server. Дополнительные сведения о строках соединения см. в разделе Соединения с базой данных.

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()

Синхронизация баз данных

После провизионирования баз данных SQL Azure и SQL Server с использованием общей области их можно синхронизировать с помощью двух объектов SqlSyncProvider и объекта SyncOrchestrator. Поскольку SQL Azure является общей средой, она содержит функции, которые позволяют избежать использования слишком большого количества ресурсов одним пользователем. При выполнении синхронизации особое внимание следует уделить ограничениям потребления ресурсов, также называемым регулированием, что означает возможность прекращения выполнения транзакции Windows Azure, если она выполняется слишком долго или если ее выполнение приводит к потреблению слишком большого количества ресурсов ЦП или ввода-вывода. Sync Framework управляет регулированием несколькими способами.

  • При ошибке применения изменений Sync Framework по умолчанию выполняет еще две попытки выполнения транзакции, а затем прекращает выполнение синхронизации.

  • При ошибке применения изменений Sync Framework вызывает событие DbConnectionFailure. В приложении синхронизации может быть выполнена регистрация для обработки этого события, при этом приложение может выбрать последующее действие: повтор попытки транзакции или отмена синхронизации.

  • Свойство MaximumApplicationTransactionSize можно использовать для задания ограничения размеров всех транзакций до указанного количества килобайт. Благодаря этому можно избежать необходимости в регулировании путем задания размера транзакции меньше ограничения, задаваемого при регулировании. Обычно это значение задается в диапазоне от 10 мегабайт до 50 мегабайт. Чем выше пропускная способность используемой сети, тем выше может быть это значение. Не рекомендуется задавать значение меньше 1 мегабайта, поскольку это приведет к резкому снижению производительности. Следует помнить, что это значение должно быть больше наибольшей возможной строки в области синхронизации. В противном случае при выполнении синхронизации будет вызвана ошибка. Если это значение задано, Sync Framework выполняет все операции по разделению пакетов изменений таким образом, чтобы размер каждой транзакций не превышал максимальный.

Также при работе с SQL Azure следует помнить, что выполнение команды SQL может занять время, превышающее ожидаемое, что приведет к перегрузке приложения, хотя более разумно было бы прекратить выполнение синхронизации и повторить попытку в другое время. Или, поскольку по умолчанию для выполнения команды задается время ожидания ADO.NET, равное 30 секундам, может потребоваться задать большее время ожидания, если выполнение запланированных команд может длиться более 30 секунд. Чтобы изменить значение времени ожидания, задаваемое по умолчанию, задайте для свойства SqlSyncProvider..::..CommandTimeout указанное количество секунд для ожидания до отмены отправки команды SQL Azure или задайте для свойства значение 0, чтобы указать на отсутствие времени ожидания для команды.

В следующем примере для команды SQL Azure время ожидания задается равным 60 секундам, максимальный размер транзакции для применения изменений задается равным 50 мегабайтам, и выполняется регистрация обработчика для события DbConnectionFailure. Эти настройки не являются обязательными и не требуются для выполнения синхронизации. Затем в примере выполняется синхронизация баз данных SQL Azure и SQL Server. После выполнения этого кода в базе данных будут содержаться идентичные данные для указанной области.

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")

В приведенном ниже примере кода описан обработчик событий DbConnectionFailure. Этот обработчик события проверяет количество повторных попыток и переопределяет настройки по умолчанию для 10 попыток применения изменений до остановки синхронизации.

       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

Синхронизация SQL Azure и SQL Server Compact

Поскольку данные синхронизированы в базу данных SQL Azure, она доступна для синхронизации с такими клиентами, как база данных SQL Server Compact. Часто клиентам не требуются все данные. Для этого сценария с помощью отфильтрованных областей можно гарантировать получение клиентом только нужного ему подмножества данных. Создание шаблона фильтра на основе параметра в базе данных SQL Azure позволяет клиентам в соответствии с требованиями указывать параметры значений и создавать отфильтрованные области. После определения и провизионирования отфильтрованной области базы данных SQL Azure и SQL Server Compact могут быть синхронизированы в любой момент с помощью кода, схожего с кодом, который использовался для синхронизации баз данных SQL Server и SQL Server Compact.

Провизионирование шаблона фильтра на основе параметров

Для провизионирования выборочной синхронизации базы данных SQL Azure сначала необходимо определить шаблон отфильтрованной области. Шаблон отфильтрованной области описывает набор таблицы в отфильтрованной области, столбцы, используемые для фильтрации, и предложение фильтра, описывающее связь между столбцами и параметры фильтра. Поскольку в базе данных уже содержится область синхронизации, укажите, что Sync Framework должен пропустить создание стандартного набора хранимых процедур, а вместо этого должен создать только необходимые для дополнительной области. Для этого следует указать Skip для метода SetCreateProceduresDefault и Create для метода SetCreateProceduresForAdditionalScopeDefault. Также следует помнить, что, если таблица уже является частью области синхронизации, для нее уже создана таблица отслеживания. Если новая отфильтрованная область содержит эту же таблицу, Sync Framework автоматически добавляет столбец фильтра к таблице отслеживания. Для этого для столбца фильтра необходимо допустить значения null, либо для этого столбца должно быть определено значение по умолчанию.

Дополнительные сведения см. в разделе Как фильтровать данные для синхронизации базы данных (SQL Server).

В следующем примере описывается создание шаблона области для фильтрации на основе параметров. Шаблон области содержит две таблицы, фильтрация одной из которых выполняется по содержащемуся в ней столбцу 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()

Провизионирование отфильтрованной области

Поскольку шаблон отфильтрованной области уже определен в базе данных SQL Azure, его можно использовать для создания отфильтрованных областей и для провизионирования других баз данных, таких как клиентская база данных SQL Server Compact. Чтобы создать отфильтрованную область, задайте имя для новой области и определите значения всех параметров фильтра. После этого отфильтрованную область можно использовать для провизионирования базы данных SQL Azure и других баз данных.

В следующем примере описывается определение отфильтрованной области, включающей только элементы из таблицы Sales.Customer, имеющие значение CustomerTypeRetail. Отфильтрованная область используется для провизионирования базы данных SQL Azure и клиентской базы данных SQL Server Compact для выполнения выборочной синхронизации.

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()

Синхронизация баз данных

После провизионирования баз данных SQL Azure и SQL Server Compact с использованием общей отфильтрованной области их можно синхронизировать с помощью объектов SqlSyncProvider, SqlCeSyncProvider и SyncOrchestrator. В следующем примере описывается, как это сделать.

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")

Полный пример

Приведенный ниже пример кода содержит все ранее описанные примеры и дополнительный код для выполнения синхронизации. Для выполнения примера необходим класс Utility, описанный в разделе Инструкции по классу Utility для поставщика базы данных.

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

См. также

Другие ресурсы

Синхронизация SQL Server и SQL Server Compact