針對同步進行設置
在可以使用 Sync Framework 同步數據庫之前,需要通過稱為“設置(provisioning)”的流程配置它。所需的設置類型因數據庫類型而異。本篇提供有關設置 SQL Server 和 SQL Server Compact 數據庫的背景信息、操作步驟以及完整代碼示例。
了解設置和取消設置(Provision and Deprovision)
為同步配置數據庫的第一步是定義一個作用域,該作用域標識要同步的內容。在您定義同步作用域后,就可以使用該同步作用域來設置數據庫,以便創建變更跟蹤和元數據管理基礎結構,該基礎結構由元數據表、觸發器和存儲過程構成。在設置了某一數據庫后,可以通過使用某一提供程序(例如 SqlSyncProvider)來表示該數據庫和使用 SyncOrchestrator 對象管理同步會話並連接到其他同步提供程序以實現數據同步。為同步設置數據庫是有別於與其他數據庫同步的單獨任務,這部分代碼通常位於單獨的應用程序中。
設置(Provision)
在設置(Provision)數據庫時,通常會在數據庫中創建以下某些或全部元素:
- 在同步作用域中包含的基表。
- 作用域中每個基表的一個跟蹤表。該跟蹤表跟蹤對關聯基表進行的變更。
- 在直接對基表進行更改時更新跟蹤表的觸發器。
- 用於同步操作的存儲過程,例如枚舉變更、插入變更、更新數據或刪除數據。通過設置對象的SetUseBulkProceduresDefault方法可以為SQL Server 2008 和 SQL Azure 數據庫創建使用表值函數一次執行多行的插入、更新和刪除操作的成批過程。
- 包含同步作用域信息的特殊表,例如 scope_info 表。如果這些表尚不存在,則創建這些表。
數據庫設置對象提供了相應方法來控制上面這些同步元素的創建,比如:基表創建由 SetCreateTableDefault 方法控制,跟蹤表創建由 SetCreateTrackingTableDefault 方法控制。此外,同步元素可以創建在數據庫的單獨架構(Schema)中,這是通過 SqlSyncScopeProvisioning類的ObjectSchema 屬性實現的。
可通過調用 SqlSyncScopeProvisioning.Apply 或 SqlCeSyncScopeProvisioning.Apply方法直接應用設置;或者,對於 SQL Server 數據庫,可以創建一個腳本並在以后運行該腳本來設置數據庫。若要創建設置腳本,請調用 SqlSyncScopeProvisioning.Script 方法。
取消設置(Deprovision)
如果您不再需要某一作用域,則可以通過調用SqlSyncScopeDeprovisioning.DeprovisionScope 或 SqlCeSyncScopeDeprovisioning.DeprovisionScope,刪除該作用域及其關聯的元數據表、觸發器和存儲過程。在已刪除某一作用域后,該作用域不再用於同步。如果某一數據庫元素(例如元數據表)由多個作用域使用,則在使用該元素的最后一個作用域被刪除前,將不刪除該元素。例如,您具有名為 Customers 的一個表,並且定義兩個分別名為 RetailCustomers 和 WholesaleCustomers 的作用域,並且這兩個作用域包含 Customers 表。在您刪除 WholesaleCustomers 作用域時,用於 Customers 表的元數據表不刪除,因為它仍由 RetailCustomers 作用域使用。
如果您使用基於參數的篩選器來篩選 SQL Server 或 SQL Azure 數據庫中的同步數據,則首先創建一個篩選器模板,然后基於該篩選器模板創建篩選的作用域。您還可以通過調用 DeprovisionTemplate,輕松地刪除該篩選器模板和基於該模板創建的所有經過篩選的作用域,以及所有關聯的元數據表、觸發器和存儲過程。例如,您創建一個 customerstate_template 模板,該模板通過使用 state 參數進行篩選。您基於 customerstate_template 創建兩個經過篩選的作用域 customers_WA 和 customers_OR。在您刪除 customerstate_template 時,customers_WA 和 customers_OR 也刪除。
您還可以通過調用SqlSyncScopeDeprovisioning.DeprovisionStore 或 SqlCeSyncScopeDeprovisioning.DeprovisionStore,從數據庫中刪除所有作用域和篩選器以及所有同步元數據表、觸發器和存儲過程。此外,因為刪除單獨的作用域和篩選器模板將僅刪除作用域級別和模板級別的元數據,而不刪除數據庫級別的元數據,所以,SqlSyncScopeDeprovisioning.DeprovisionStore 或 SqlCeSyncScopeDeprovisioning.DeprovisionStore 可用於在刪除了所有作用域和模板后清除剩余的同步元數據表。
設置數據庫
同步作用域和同步模板
我們之前已經了解到,同步作用域是對進行同步的對象的一種邏輯分組。對於數據庫同步,一個同步組通常是一組數據表,並且數據表可以被過濾。同時一個數據表可以被包含在一個或多個同步組中。
有些時候,我們需要使用基於參數的篩選器來篩選 SQL Server 或 SQL Azure 數據庫中的同步數據,則首先創建一個篩選器模板,然后基於該篩選器模板創建篩選的作用域。比如,每個銷售人員只對自己相關的訂單數據感興趣,那么我們就需要針對每個銷售人員創建同步作用域,這時,我們就可以使用同步模板來簡化同步作用域的創建過程,甚至通過訂閱的手段來實現這一過程的自動化。關於篩選器模板的詳細介紹請參考下篇“如何為數據庫同步篩選數據”。
定義同步作用域
下面的代碼定義了一個名為filtered_customer 的同步作用域,並為其添加了兩個表:Customer和CustomerContact。因為這些表已經存在於服務器數據庫之中,所以使用GetDescriptionForTable方法來檢索表的架構。Customer表的所有列都包含在同步作用域中,但是CustomerContact表只包含了兩列。
DbSyncScopeDescription scopeDesc = new DbSyncScopeDescription("filtered_customer");
// Definition for Customer.
DbSyncTableDescription customerDescription =
SqlSyncDescriptionBuilder.GetDescriptionForTable("Sales.Customer", serverConn);
scopeDesc.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, serverConn);
scopeDesc.Tables.Add(customerContactDescription);
設置服務器數據庫
下面的代碼為filtered_customer 同步作用域創建了一個設置對象,並且指定所有同步元素創建在"Sync"數據庫架構中。代碼還為Customer表指定了一個過濾條件,只有滿足該條件的數據行才會被同步。定義一個過濾條件分為兩部分:調用AddFilterColumn指定過濾列名為”CustomerType”,它會被添加到變更跟蹤表以跟蹤Customer表的改變。調用FilterClause指定過濾條件本身,它是不包含WHERE關鍵字的WHERE子句。[side]是變更跟蹤表的別名。定義好設置選項后,Apply方法會在服務器數據庫中創建變更跟蹤基礎結構,並且把設置腳本寫到一個文件中。
SqlSyncScopeProvisioning serverConfig = new SqlSyncScopeProvisioning(serverConn, scopeDesc);
serverConfig.ObjectSchema = "Sync";
// Specify which column(s) 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.
serverConfig.Tables["Sales.Customer"].AddFilterColumn("CustomerType");
serverConfig.Tables["Sales.Customer"].FilterClause = "[side].[CustomerType] = 'Retail'";
// Configure the scope and change-tracking infrastructure.
serverConfig.Apply();
// Write the configuration script to a file. You can modify
// this script if necessary and run it against the server
// to customize behavior.
File.WriteAllText("SampleConfigScript.txt", serverConfig.Script());
設置客戶端數據庫
我們可以通過兩種方式來設置客戶端數據庫:
1. 基於從服務器或另外的客戶端數據庫獲取的scope/作用域信息,完全初始化一個SQL Server或SQL Server Compact客戶端數據庫。我們可以通過SqlSyncDescriptionBuilder和SqlCeSyncDescriptionBuilder對象來獲取同步作用域的架構信息,從而在客戶端數據庫創建同步對象。
2. 通過一個已經存在的客戶端數據庫來對一個SQL Server Compact客戶端數據庫進行快照初始化。
快照初始化的主要目的是減少初始化客戶端數據庫所需的時間。更多關於快照初始化的知識請參照本篇“使用快照設置數據庫”的詳細介紹。
下面的代碼示例首先從服務器獲取同步作用域信息,並使用它們來設置一個SQL Server Compact客戶端數據庫。然后,基於該SQL Server Compact客戶端數據庫的作用域信息來設置另一個SQL Server客戶端數據庫。
// 創建一個SQL Server Compact數據庫並用從服務器端獲取的作用域信息來設置它
// Compact數據庫不支持單獨的schema,
// 所以我們通過為所有的同步對象增加前綴"Sync"來使他們易於區分
Utility.DeleteAndRecreateCompactDatabase(Utility.ConnStr_SqlCeSync1, true);
Utility.DeleteAndRecreateCompactDatabase(Utility.ConnStr_SqlCeSync2, false);
DbSyncScopeDescription clientSqlCe1Desc = SqlSyncDescriptionBuilder.GetDescriptionForScope("filtered_customer", null, "Sync", serverConn);
SqlCeSyncScopeProvisioning clientSqlCe1Config = new SqlCeSyncScopeProvisioning(clientSqlCe1Conn, clientSqlCe1Desc);
clientSqlCe1Config.ObjectPrefix = "Sync";
clientSqlCe1Config.Apply();
// 通過從SQL Server Compact數據庫中獲取的同步作用域信息來設置一個SQL Server客戶端數據庫
// 當然我們也可以從服務器端獲取作用域信息
DbSyncScopeDescription clientSqlDesc = SqlCeSyncDescriptionBuilder.GetDescriptionForScope("filtered_customer", "Sync", clientSqlCe1Conn);
SqlSyncScopeProvisioning clientSqlConfig = new SqlSyncScopeProvisioning(clientSqlConn, clientSqlDesc);
clientSqlConfig.ObjectSchema = "Sync";
clientSqlConfig.Apply();
取消設置數據庫
下面的代碼示例為我們展示了如何:
- 在客戶端數據庫中取消設置一個同步作用域
- 在服務器數據庫中取消設置篩選器模板和相關的作用域
- 完全取消設置一個客戶端數據庫,這樣所有的同步對象都會被刪除
刪除一個作用域
下面的示例在一個SQL Server客戶端數據庫中刪除RetailCustomers作用域。同時,刪除作用域的腳本被保存到了一個文件之中,這個腳本可以用來執行以刪除其他數據庫中的RetailCustomers作用域。淡然,這個步驟對於刪除一個同步作用域來說是可選的。
// 在SQL Server客戶端數據庫中刪除RetailCustomers作用域
SqlSyncScopeDeprovisioning clientSqlDepro = new SqlSyncScopeDeprovisioning(clientSqlConn);
// 首先把取消設置的SQL腳本保存下來,以便取消設置其他的SQL Server客戶端數據庫
// 這一步是可選的
File.WriteAllText("SampleDeprovisionScript.txt",
clientSqlDepro.ScriptDeprovisionScope("RetailCustomers"));
// 刪除作用域
clientSqlDepro.DeprovisionScope("RetailCustomers");
刪除一個篩選器模板
在刪除一個篩選器模板之前,我們通常需要查看從這個篩選器模板創建出來的同步作用域,因為當這個篩選器模板被刪除(Deprovision)時,所有這些作用域也會被刪除。下面的SQL腳本可以用來查找由customertype_template篩選器模板所創建的篩選作用域。
-- Find all filtered scopes that were created from the filtered scope template named 'customertype_template'.
select sync_scope_name from scope_info
where scope_config_id =
(select template_config_id from scope_templates
where template_name = N'customertype_template')
下面的示例從SQL Server服務器數據庫中刪除customertype_template篩選器模板。在刪除該模板的同時也會刪除由它創建出來的作用域RetailCustomers和WholesaleCustomers。
// 從服務器數據庫中刪除"customertype_template"模板
// 這樣也會刪除所有依賴與該模板的作用域
SqlSyncScopeDeprovisioning serverSqlDepro = new SqlSyncScopeDeprovisioning(serverConn);
serverSqlDepro.DeprovisionTemplate("customertype_template");
刪除所有同步對象
下面的示例從一個SQL Server Compact客戶端數據庫中刪除所有的同步對象,包括:同步元數據表、觸發器和存儲過程。
// 在SQL Server Compact數據庫這哦你刪除所有的同步對象
SqlCeSyncScopeDeprovisioning clientSqlCeDepro = new SqlCeSyncScopeDeprovisioning(clientSqlCe1Conn);
clientSqlCeDepro.DeprovisionStore();
使用快照設置數據庫
如果我們需要對多個SQL Server Compact數據庫的同步進行設置,那么我們可以使用數據庫快照來減少初始化所需的時間。一個快照是特別准備的,包含了表架構、數據(可選)、和變更跟蹤基礎結構的SQL Server Compact數據庫。在我們對一個SQL Server Compact數據庫作完全初始化后,我們可以為其創建一個快照,該快照可以拷貝至其他需要同步的SQL Server Compact數據庫。對數據庫應用快照的過程比完全初始化要高效得多。
下面的示例為我們展示了通過從服務器數據庫獲取的作用域信息來設置Compact數據庫,然后使用該數據庫的快照來初始化另外一個數據庫。
static void SynchronizationUsingSnapshot()
{
// 通過從服務器數據庫獲取的作用域信息來設置Compact數據庫SyncCompactDB2.sdf
SqlCeConnection clientConn = new SqlCeConnection(@"Data Source='D:\Sync Framework\CompactDB\SyncCompactDB2.sdf'");
SqlConnection serverConn = new SqlConnection("Data Source=localhost; Initial Catalog=SyncDB; Integrated Security=True");
DbSyncScopeDescription scopeDesc = SqlSyncDescriptionBuilder.GetDescriptionForScope("ProductsScope", serverConn);
SqlCeSyncScopeProvisioning clientProvision = new SqlCeSyncScopeProvisioning(clientConn, scopeDesc);
clientProvision.Apply();
// 從SQL Server Compact數據庫創建一個快照,該快照將用於初始化其他的Compact數據庫
// 盡管我們可以從其他數據庫獲取作用域信息來初始化,但快照的使用為Compact數據庫提供了一個更加快捷方便的部署方案。
// SyncCompactDB3.sdf為不存在的Compact數據庫,將在GenerateSnapshot方法中自動創建
string newCompactDB = @"D:\Sync Framework\CompactDB\SyncCompactDB3.sdf";
SqlCeSyncStoreSnapshotInitialization syncStoreSnapshot = new SqlCeSyncStoreSnapshotInitialization();
syncStoreSnapshot.GenerateSnapshot(clientConn, newCompactDB);
// 對使用快照初始化的SyncCompactDB3.sdf執行同步,因為快照中已經包含了服務器中的數據
// 所以本次同步將沒有數據被同步,直到一方的數據發生變化
SyncOrchestrator syncOrchestrator = new SyncOrchestrator();
syncOrchestrator.LocalProvider = new SqlCeSyncProvider("ProductsScope", clientConn);
syncOrchestrator.RemoteProvider = new SqlSyncProvider("ProductsScope", serverConn);
syncOrchestrator.Direction = SyncDirectionOrder.UploadAndDownload;
SyncOperationStatistics syncStats = syncOrchestrator.Synchronize();
DisplayStats(syncStats);
}
static void DisplayStats(SyncOperationStatistics syncStats)
{
// 輸出統計數據
Console.WriteLine("Start Time: " + syncStats.SyncStartTime);
Console.WriteLine("Total Changes Uploaded: " + syncStats.UploadChangesTotal);
Console.WriteLine("Total Changes Downloaded: " + syncStats.DownloadChangesTotal);
Console.WriteLine("Complete Time: " + syncStats.SyncEndTime);
Console.WriteLine(String.Empty);
}