이 항목에서는 SQL Azure 데이터베이스를 SQL Server 데이터베이스 및 SQL Server Compact 데이터베이스와 동기화할 수 있도록 구성하는 방법 및 SQL Azure 데이터베이스를 중간 데이터베이스로 사용하여 내부 SQL Server 데이터베이스에서 웹으로 데이터를 동기화하고 웹에서 SQL Server Compact 클라이언트 데이터베이스로 데이터를 동기화하는 방법을 보여 줍니다. 이 항목의 예제에서는 다음과 같은 Sync Framework 클래스를 중점적으로 설명합니다.
SQL Azure 동기화 이해
SQL Azure Database에 데이터를 저장하면 인터넷에 연결할 수 있는 컴퓨터에서 사용자의 데이터에 안전하게 액세스하는 등 많은 혜택을 누릴 수 있습니다. Sync Framework를 사용하여 회사의 SQL Server 데이터베이스와 SQL Azure 데이터베이스 사이에 데이터를 동기화하면 내부 SQL Server 데이터베이스에 대한 연결을 제공하지 않고도 사용자의 데이터 중 일부 또는 전부를 다른 사용자가 사용할 수 있도록 지정할 수 있습니다. 동기화를 위해 SQL Azure 데이터베이스를 구성한 후 원격으로 근무하는 영업 사원과 같이 비즈니스 방화벽 외부에서 근무하는 사용자가 데이터를 SQL Server Compact 데이터베이스와 같은 클라이언트 데이터베이스와 동기화할 수 있습니다. 필드의 데이터 변경 내용을 다시 SQL Azure 데이터베이스와 동기화하고 내부 SQL Server 데이터베이스와 동기화할 수 있습니다.
대개 2계층 아키텍처 또는 N계층 아키텍처라는 두 가지 방법을 사용하여 SQL Server 데이터베이스를 SQL Azure 데이터베이스와 동기화하는 응용 프로그램을 구성할 수 있습니다.
2계층 아키텍처: 다른 SQL Server 데이터베이스와 마찬가지로 Sync Framework가 로컬 컴퓨터에서 실행되고 SqlSyncProvider 개체를 사용하여 SQL Azure 데이터베이스에 직접 연결합니다. 이 항목에서는 2계층 아키텍처를 중점적으로 다룹니다.
N계층 아키텍처: Sync Framework 데이터베이스 공급자가 Windows Azure에서 호스팅하는 서비스에서 실행되고 로컬 컴퓨터에서 실행되는 프록시 공급자와 통신합니다. 자세한 내용은 방법: Windows Azure에 Sync Framework 배포를 참조하십시오.
동기화 아키텍처에 대한 자세한 내용은 데이터베이스 동기화에 대한 아키텍처 및 클래스를 참조하십시오.
SQL Server 및 SQL Azure 동기화
내부 데이터를 웹에 배치하려면 먼저 SQL Azure 데이터베이스를 만들고, SQL Azure 데이터베이스와 SQL Server 데이터베이스 사이에 동기화할 항목의 범위를 정의하고, 데이터베이스가 다른 데이터베이스와 동기화할 수 있도록 데이터베이스를 프로비전합니다. 데이터베이스가 동기화에 알맞도록 구성된 후에는 SQL Server 데이터베이스와 동기화하는 데 사용하는 동일한 Sync Framework 코드를 사용하여 언제든지 해당 데이터베이스를 동기화할 수 있습니다. 다음 섹션에서는 데이터베이스를 프로비전하고 동기화하는 방법을 설명합니다.
동기화를 위해 SQL Azure 데이터베이스 프로비전
다른 데이터베이스가 SQL Azure 데이터베이스와 동기화할 수 있으려면 먼저 동기화를 위해 SQL Azure 데이터베이스를 프로비전해야 합니다. 데이터베이스를 프로비전하면 Sync Framework에서 동기화를 수행하는 데 필요한 메타데이터 테이블 및 저장 프로시저가 만들어집니다. SQL Server 데이터베이스가 이미 존재하며 새 SQL Azure 데이터베이스가 사용되는 경우 먼저 SQL Server 데이터베이스의 테이블을 기준으로 하는 동기화 범위를 정의한 후 SQL Server 및 SQL Azure 데이터베이스를 프로비전합니다.
참고
SQL Azure 데이터베이스에서 프로비전이 실패하면 프로비전 트랜잭션을 롤백할 수 없는 경우가 있습니다. 이러한 경우 DbPartiallyProvisionedException이 발생합니다. 따라서 SQL Azure 데이터베이스 프로비전 중 DbPartiallyProvisionedException이 발생할 경우 데이터베이스 프로비전을 다시 시도하기 전에 먼저 실패한 범위나 템플릿의 프로비전을 해제해야 프로비전이 실패하지 않습니다.
다음 예제에서는 내부 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는 공유 환경이므로 너무 많은 리소스를 사용하는 사용자가 없도록 하는 기능을 포함합니다. 동기화에 대해 특별히 고려해야 할 사항은 제한이라고 하는 리소스 사용 제한이 있다는 점입니다. 즉, 트랜잭션이 너무 오래 실행되거나 프로세스에서 과도한 CPU 또는 I/O 로드를 생성하는 경우 Windows Azure에서 이러한 트랜잭션을 중지할 수 있습니다. Sync Framework에서는 다양한 방식으로 제한을 처리합니다.
변경 내용 적용이 실패하면 Sync Framework에서 기본적으로 동기화를 중지하기 전에 두 번 이상 트랜잭션을 시도합니다.
변경 내용 적용이 실패하면 Sync Framework에서 DbConnectionFailure 이벤트를 발생시킵니다. 동기화 응용 프로그램은 이 이벤트를 처리하도록 등록할 수 있으며 트랜잭션을 다시 시도하거나 동기화를 취소할지를 결정할 수 있습니다.
각 트랜잭션의 크기를 지정된 수(KB)로 제한하도록 MaximumApplicationTransactionSize 속성을 설정할 수 있습니다. 이렇게 하면 트랜잭션 크기를 제한 한도 아래로 유지하여 제한을 방지할 수 있습니다. 이 값에 대한 일반적인 설정은 10MB에서 50MB 사이입니다. 네트워크 대역폭이 높을수록 이 값도 높을 수 있습니다. 1MB 미만의 값은 성능을 크게 저하시킬 수 있으므로 권장되지 않습니다. 이 값은 동기화 범위에서 가장 큰 가능한 행보다 커야 합니다. 그렇지 않으면 동기화가 실패합니다. 이 값이 설정되면 지정된 최대 크기 제한 아래에서 각 트랜잭션이 유지되도록 Sync Framework에서 변경 일괄 처리를 나누는 모든 작업을 처리합니다.
SQL Azure에서 작업할 때 고려해야 할 또 다른 사항은 동기화를 중지하고 다른 시간에 다시 시도하는 것이 더 나은 경우 적용을 그대로 보유함으로써 SQL 명령을 완료하는 데 예상보다 많은 시간이 걸릴 수 있다는 점입니다. 또는 명령에 대한 기본 제한 시간이 ADO.NET 제한 시간인 30초이므로 명령 실행 시간이 30초를 초과할 것으로 예상하는 경우 제한 시간을 더 길게 지정할 수 있습니다. 기본 제한 시간을 변경하려면 SqlSyncProvider.CommandTimeout 속성을 특정 수(초)로 설정하여 지정된 시간이 지나면 SQL Azure에 보낸 명령이 취소되도록 하거나, 속성 값을 0으로 설정하여 명령이 시간 제한 없이 실행되도록 합니다.
다음 예제에서는 SQL Azure 명령에 대해 60초의 제한 시간을 설정하고, 변경 내용 적용에 대한 최대 트랜잭션 크기를 50MB로 설정하고, 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 Server 및 SQL Server Compact 데이터베이스를 동기화하는 데 사용한 코드와 유사한 코드를 사용하여 언제든지 SQL Azure 및 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 데이터베이스는 물론 다른 데이터베이스도 프로비전할 수 있습니다.
다음 예제에서는 CustomerType 값이 Retail인 Sales.Customer 테이블의 항목만 포함하는 필터링된 범위를 정의하는 방법을 보여 줍니다. 필터링된 범위가 정의되면 필터링된 동기화를 위해 이러한 범위를 사용하여 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 클래스가 필요합니다.
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