共用方式為


逐步解說:擴充本機資料庫快取以支援雙向同步處理

您可以在專案中加入 [本機資料庫快取] 項目,設定本機 SQL Server Compact 3.5 資料庫快取,以及產生一組啟用 Microsoft Synchronization Services for ADO.NET 的部分類別。 因為 Visual Studio 會產生部分類別,您可以撰寫程式碼以加入同步處理功能,同時仍然能夠檢視與變更 [設定資料同步處理] 對話方塊中的設定。 如需部分類別的詳細資訊,請參閱 HOW TO:將類別分割成部分類別 (類別設計工具)

根據預設,[設定資料同步處理] 對話方塊僅能讓您針對下載作業設定 Synchronization Services。 這表示在您設定資料同步處理後,呼叫 Synchronize() 時只會將變更由伺服器下載至用戶端資料庫。 擴充同步處理程式碼最常見的方法之一,是設定雙向 (Bidirectional) 同步處理。 如此一來,您就能由用戶端將變更上載至伺服器。 若要啟用雙向同步處理,我們建議您以下列方式擴充產生的程式碼:

  • 將同步處理方向設定為雙向。

  • 加入程式碼以處理同步處理衝突。

  • 由同步處理命令移除伺服器追蹤資料行。

必要條件

在開始這個逐步解說前,您必須先完成逐步解說:建立偶爾連接的應用程式。 完成上述的逐步解說後,您會有包含 [本機資料庫快取] 項目與 Windows Form 應用程式的專案,即能由 Northwind Customers 資料表將變更下載至 SQL Server Compact 資料庫。 現在您已準備就緒,可以載入此逐步解說方案並加入雙向功能。

注意事項注意事項

您的電腦可能會在下列說明中,以不同名稱或位置顯示某些 Visual Studio 使用者介面項目。 您所擁有的 Visual Studio 版本以及使用的設定會決定這些項目。 如需詳細資訊,請參閱 Visual Studio 設定

若要開啟 OCSWalkthrough 方案

  1. 開啟 Visual Studio。

  2. 在 [檔案] 功能表上開啟現有的方案或專案,並找出 OCSWalkthrough 方案, 也就是 OCSWalkthrough.sln 檔案。

設定同步處理方向

[設定資料同步處理] 對話方塊能讓您將 SyncDirection() 屬性設定為 DownloadOnly() 或 Snapshot()。 若要啟用雙向同步處理,則針對要啟用將變更上載的功能的每個資料表,將 SyncDirection() 屬性設定為 Bidirectional()。

若要設定同步處理方向

  1. 以滑鼠右鍵按一下 [NorthwindCache.sync],然後按一下 [檢視程式碼。 您第一次做這個動作時,Visual Studio 會在 [方案總管] 中的 [NorthwindCache.sync] 節點下建立一個 NorthwindCache 檔案。 這個檔案中包含了一個 NorthwindCacheSyncAgent 部分類別,您可以視需要加入其他的類別。

  2. 在 NorthwindCache 類別檔案中加入程式碼,讓 NorthwindCacheSyncAgent.OnInitialized() 方法類似下列程式碼:

    partial void OnInitialized()
    {
        this.Customers.SyncDirection = 
        Microsoft.Synchronization.Data.SyncDirection.Bidirectional;
    }
    
    Private Sub OnInitialized()
        Me.Customers.SyncDirection = 
        Microsoft.Synchronization.Data.SyncDirection.Bidirectional
    End Sub
    
  3. 在 [程式碼編輯器] 中開啟 Form1。

  4. 在 Form1 檔案中,修改在 SynchronizeButton_Click 事件處理常式中的程式碼行,以包含上載和下載統計資料:

    MessageBox.Show("Changes downloaded: " +
        syncStats.TotalChangesDownloaded.ToString() + 
        Environment.NewLine +
        "Changes uploaded: " + 
        syncStats.TotalChangesUploaded.ToString());
    
    MessageBox.Show("Changes downloaded: " & _
        syncStats.TotalChangesDownloaded.ToString & _
        Environment.NewLine & _
        "Changes uploaded: " & _
        syncStats.TotalChangesUploaded.ToString)
    

測試應用程式

現在應用程式已設定為會在同步處理期間一併執行上載與下載。

若要測試應用程式

  1. 按 F5。

  2. 更新表單中的一項記錄,然後按一下 [儲存] 按鈕 (工具列上的磁碟圖示)。

  3. 按一下 [開始同步處理]。

  4. 隨即會出現一個訊息方塊,內含有關同步處理記錄的資訊。 這些統計資料會顯示有一列已上載,也下載一列,雖然在伺服器上沒有變更。 發生此額外下載的原因,是因為來自用戶端的變更在套用至伺服器後,會回應 (Echo) 至用戶端。 如需詳細資訊,請參閱 HOW TO:使用自訂變更追蹤系統中的<判斷變更資料的用戶端>一節 (英文)。

  5. 按一下 [確定] 關閉訊息方塊,但讓應用程式繼續執行。

現在您將在用戶端和伺服器上同時變更同樣的記錄,在同步處理期間強迫產生衝突 (並行違規)。

若要測試應用程式並強迫產生衝突

  1. 更新表單中的一項記錄,然後按一下 [儲存] 按鈕。

  2. 在應用程式執行中,使用 [伺服器總管]/[資料庫總管] (或其他資料庫管理工具) 連接至伺服器資料庫。

  3. 為示範衝突解決方式的預設行為,在 [伺服器總管]/[資料庫總管] 中,對您在表單中所更新的同一筆記錄進行更新,但是變更為不同的值,然後認可變更 (離開修改過的資料列即可)。

  4. 返回表單並按一下 [開始同步處理]。

  5. 驗證在應用程式方格中與伺服器資料庫中的更新資料。 請注意,您在伺服器上所做的更新,已覆寫用戶端上的更新。 如需如何變更此衝突解決方法之行為的資訊,請參閱本主題的下一節「加入程式碼以處理同步處理衝突」。

加入程式碼以處理同步處理衝突

在 Synchronization Services 中,如果有一個資料列在同步處理的間隔中,同時在用戶端與伺服器上受到變更,就會出現衝突。 Synchronization Services 提供一組功能,可用來偵測及解決衝突。 在本節中,您將加入基本的處理方式,解決同一個資料列同時在用戶端與伺服器上更新所造成的衝突。 其他類型的衝突包括了同一個資料列在一個資料庫中被刪除,但在另一個資料庫中卻已更新,或有主索引鍵重複的資料列同時插入兩個資料庫的情況。 如需偵測與解決衝突之方法的詳細資訊,請參閱 HOW TO:處理資料衝突與錯誤 (英文)。

注意事項注意事項

範例程式碼提供了衝突處理的基本範例。 您處理衝突的方式要根據您應用程式和商務邏輯的需求而定。

加入程式碼以處理伺服器 ApplyChangeFailed 事件與用戶端 ApplyChangeFailed 事件。 當資料列由於衝突或錯誤而無法套用時,就會引發這些事件。 處理這些事件的方法會檢查衝突類型,並指定將用戶端變更強制寫入伺服器資料庫,以解決用戶端更新 / 伺服器更新衝突。 將更新套用至伺服器資料庫的同步處理命令,含有辨識何時應強制執行變更的邏輯。 這項命令會包含在本主題下一節「由同步處理命令移除伺服器追蹤資料行」的程式碼中。

您為加入衝突處理所執行的步驟,會根據您使用的是 C# 或 Visual Basic 而有所不同。

若要加入衝突處理

  • 如果您使用 C#,請將下列程式碼加入至 NorthwindCache.cs 和 Form1.cs 中。 在 NorthwindCache.cs 中,將下列程式碼加到 NorthwindCacheSyncAgent 類別的結尾之後:

    public partial class NorthwindCacheServerSyncProvider
    {
    
        partial void OnInitialized()
        {
            this.ApplyChangeFailed +=
                new System.EventHandler<Microsoft.Synchronization.Data.ApplyChangeFailedEventArgs>
                (NorthwindCacheServerSyncProvider_ApplyChangeFailed);
        }
    
        private void NorthwindCacheServerSyncProvider_ApplyChangeFailed(object sender,
            Microsoft.Synchronization.Data.ApplyChangeFailedEventArgs e)
        {
    
        if (e.Conflict.ConflictType ==
            Microsoft.Synchronization.Data.ConflictType.ClientUpdateServerUpdate)
            {
    
            // Resolve a client update / server update conflict by force writing
            // the client change to the server database.
            System.Windows.Forms.MessageBox.Show("A client update / server update conflict " +
                                                    "was detected at the server.");
            e.Action = Microsoft.Synchronization.Data.ApplyAction.RetryWithForceWrite;
    
            }
    
        }
    }
    
    public partial class NorthwindCacheClientSyncProvider
    {
    
        public void AddHandlers()
        {
            this.ApplyChangeFailed +=
                new System.EventHandler<Microsoft.Synchronization.Data.ApplyChangeFailedEventArgs>
                (NorthwindCacheClientSyncProvider_ApplyChangeFailed);
        }
    
        private void NorthwindCacheClientSyncProvider_ApplyChangeFailed(object sender,
            Microsoft.Synchronization.Data.ApplyChangeFailedEventArgs e)
        {
    
            if (e.Conflict.ConflictType ==
                Microsoft.Synchronization.Data.ConflictType.ClientUpdateServerUpdate)
            {
    
                // Resolve a client update / server update conflict by keeping the 
                // client change.
                e.Action = Microsoft.Synchronization.Data.ApplyAction.Continue;
    
            }
    
        }
    }
    

    在 Form1.cs 中修改 SynchronizeButton_Click 事件處理常式中的程式碼,以呼叫您在前一個步驟中加入至 NorthwindCache.cs 的 AddHandler 方法:

    NorthwindCacheSyncAgent syncAgent = new NorthwindCacheSyncAgent();
    
    NorthwindCacheClientSyncProvider clientSyncProvider =
        (NorthwindCacheClientSyncProvider)syncAgent.LocalProvider;
    clientSyncProvider.AddHandlers();
    
    Microsoft.Synchronization.Data.SyncStatistics syncStats = 
        syncAgent.Synchronize();
    
  • 如果您使用 Visual Basic,則將下列程式碼加到 NorthwindCache.vb 中 NorthwindCacheSyncAgent 類別的 End Class 陳述式之後。

    Partial Public Class NorthwindCacheServerSyncProvider
    
        Private Sub NorthwindCacheServerSyncProvider_ApplyChangeFailed( _
            ByVal sender As Object, ByVal e As  _
            Microsoft.Synchronization.Data.ApplyChangeFailedEventArgs) _
            Handles Me.ApplyChangeFailed
    
            If e.Conflict.ConflictType = _
                Microsoft.Synchronization.Data.ConflictType.ClientUpdateServerUpdate Then
    
                ' Resolve a client update / server update conflict by force writing
                ' the client change to the server database.
                MessageBox.Show("A client update / server update" & _
                    " conflict was detected at the server.")
                e.Action = Microsoft.Synchronization.Data.ApplyAction.RetryWithForceWrite
    
            End If
    
        End Sub
    
    End Class
    
    Partial Public Class NorthwindCacheClientSyncProvider
    
        Private Sub NorthwindCacheClientSyncProvider_ApplyChangeFailed( _
            ByVal sender As Object, ByVal e As  _
            Microsoft.Synchronization.Data.ApplyChangeFailedEventArgs) _
            Handles Me.ApplyChangeFailed
    
            If e.Conflict.ConflictType = _
                Microsoft.Synchronization.Data.ConflictType.ClientUpdateServerUpdate Then
    
                ' Resolve a client update / server update conflict by keeping the 
                ' client change.
                e.Action = Microsoft.Synchronization.Data.ApplyAction.Continue
    
            End If
    
        End Sub
    
    End Class
    

若要同步處理並檢視衝突解決方法

  1. 按 F5。

  2. 更新表單中的一項記錄,然後按一下 [儲存] 按鈕。

  3. 在 [伺服器總管]/[資料庫總管] 中,對您在表單中所更新的同一筆記錄進行更新,但是變更為不同的值,然後認可變更。

  4. 返回表單並按一下 [開始同步處理]。

  5. 驗證在應用程式方格中與伺服器資料庫中的更新資料。 請注意,您在用戶端上所做的更新,已覆寫伺服器上的更新。

由同步處理命令移除伺服器追蹤資料行

建立 [本機資料庫快取] 時,用於追蹤伺服器資料庫中之變更的資料行會下載至用戶端 (在本逐步解說中,這些資料行指的是 CreationDate 和 LastEditDate)。若要支援雙向同步處理,並協助確保聚合用戶端與伺服器上的資料,請由套用變更至伺服器資料庫的 SQL 命令移除這些資料行。 您也可以由選取伺服器上的變更以套用至用戶端的命令中,將這些資料行移除,但這不是必要的。 由於用戶端資料庫中對某些結構描述變更的限制,因此無法刪除這些資料行。 如需同步處理命令的詳細資訊,請參閱 HOW TO:指定快照、下載、上載與雙向同步處理 (英文)。

注意事項注意事項

如果您使用 SQL Server 2008 變更追蹤,追蹤資料行將不會加到您的資料表中。 在這樣的情況下,您不需要改變將變更套用至伺服器的命令。

下列程式碼會重新定義兩個設定為 Customers 資料表之 SyncAdapter 物件上的屬性,分別是 InsertCommand() 和 UpdateCommand() 屬性。 這些由 [設定資料同步處理] 對話方塊產生的命令,包含對 CreationDate 和 LastEditDate 資料行的參考。 在下列程式碼中,這些命令會在CustomersSyncAdapter 類別的 OnInitialized 方法中重新定義。 因為對 CreationDate 和 LastEditDate 資料行沒有影響,因此 DeleteCommand() 屬性未重新定義。

每個 SQL 命令中的變數都會用於在 Synchronization Services、用戶端和伺服器間傳遞資料和中繼資料 (Metadata)。 下列工作階段變數會用於下方的命令:

  • @sync\_row\_count:傳回受到伺服器上前一次執行的作業所影響的資料列數。 在 SQL Server 資料庫中,@@rowcount 會提供此變數的值。

  • @sync\_force\_write:用於強制套用因為衝突或錯誤而套用失敗的變更。

  • @sync\_last\_received\_anchor:用於定義在工作階段中要同步處理的變更集。

如需工作階段變數的詳細資訊,請參閱 HOW TO:使用工作階段變數 (英文)。

若要由同步處理命令移除追蹤資料行

  • 在 NorthwindCache 類別 (NorthwindCache.vb 或 NorthwindCache.cs) 中,將下列程式碼加到 NorthwindCacheServerSyncProvider 類別的 End Class 陳述式之後。

    public partial class CustomersSyncAdapter
    {
    
        partial void OnInitialized()
        {
    
        // Redefine the insert command so that it does not insert values 
        // into the CreationDate and LastEditDate columns.
        System.Data.SqlClient.SqlCommand insertCommand = new 
            System.Data.SqlClient.SqlCommand();
    
        insertCommand.CommandText = "INSERT INTO dbo.Customers ([CustomerID], [CompanyName], " +
            "[ContactName], [ContactTitle], [Address], [City], [Region], [PostalCode], " +
            "[Country], [Phone], [Fax] )" +
            "VALUES (@CustomerID, @CompanyName, @ContactName, @ContactTitle, @Address, @City, " +
            "@Region, @PostalCode, @Country, @Phone, @Fax) SET @sync_row_count = @@rowcount";
        insertCommand.CommandType = System.Data.CommandType.Text;
        insertCommand.Parameters.Add("@CustomerID", System.Data.SqlDbType.NChar);
        insertCommand.Parameters.Add("@CompanyName", System.Data.SqlDbType.NVarChar);
        insertCommand.Parameters.Add("@ContactName", System.Data.SqlDbType.NVarChar);
        insertCommand.Parameters.Add("@ContactTitle", System.Data.SqlDbType.NVarChar);
        insertCommand.Parameters.Add("@Address", System.Data.SqlDbType.NVarChar);
        insertCommand.Parameters.Add("@City", System.Data.SqlDbType.NVarChar);
        insertCommand.Parameters.Add("@Region", System.Data.SqlDbType.NVarChar);
        insertCommand.Parameters.Add("@PostalCode", System.Data.SqlDbType.NVarChar);
        insertCommand.Parameters.Add("@Country", System.Data.SqlDbType.NVarChar);
        insertCommand.Parameters.Add("@Phone", System.Data.SqlDbType.NVarChar);
        insertCommand.Parameters.Add("@Fax", System.Data.SqlDbType.NVarChar);
        insertCommand.Parameters.Add("@sync_row_count", System.Data.SqlDbType.Int);
        insertCommand.Parameters["@sync_row_count"].Direction = 
            System.Data.ParameterDirection.Output;
    
        this.InsertCommand = insertCommand;
    
    
        // Redefine the update command so that it does not update values 
        // in the CreationDate and LastEditDate columns.
        System.Data.SqlClient.SqlCommand updateCommand = new System.Data.SqlClient.SqlCommand();
    
        updateCommand.CommandText = "UPDATE dbo.Customers SET [CompanyName] = @CompanyName, [ContactName] " +
            "= @ContactName, [ContactTitle] = @ContactTitle, [Address] = @Address, [City] " +
            "= @City, [Region] = @Region, [PostalCode] = @PostalCode, [Country] = @Country, " +
            "[Phone] = @Phone, [Fax] = @Fax " +
            "WHERE ([CustomerID] = @CustomerID) AND (@sync_force_write = 1 " +
            "OR ([LastEditDate] <= @sync_last_received_anchor)) SET @sync_row_count = @@rowcount";
        updateCommand.CommandType = System.Data.CommandType.Text;
        updateCommand.Parameters.Add("@CompanyName", System.Data.SqlDbType.NVarChar);
        updateCommand.Parameters.Add("@ContactName", System.Data.SqlDbType.NVarChar);
        updateCommand.Parameters.Add("@ContactTitle", System.Data.SqlDbType.NVarChar);
        updateCommand.Parameters.Add("@Address", System.Data.SqlDbType.NVarChar);
        updateCommand.Parameters.Add("@City", System.Data.SqlDbType.NVarChar);
        updateCommand.Parameters.Add("@Region", System.Data.SqlDbType.NVarChar);
        updateCommand.Parameters.Add("@PostalCode", System.Data.SqlDbType.NVarChar);
        updateCommand.Parameters.Add("@Country", System.Data.SqlDbType.NVarChar);
        updateCommand.Parameters.Add("@Phone", System.Data.SqlDbType.NVarChar);
        updateCommand.Parameters.Add("@Fax", System.Data.SqlDbType.NVarChar);
        updateCommand.Parameters.Add("@CustomerID", System.Data.SqlDbType.NChar);
        updateCommand.Parameters.Add("@sync_force_write", System.Data.SqlDbType.Bit);
        updateCommand.Parameters.Add("@sync_last_received_anchor", System.Data.SqlDbType.DateTime);
        updateCommand.Parameters.Add("@sync_row_count", System.Data.SqlDbType.Int);
        updateCommand.Parameters["@sync_row_count"].Direction = 
            System.Data.ParameterDirection.Output;
    
        this.UpdateCommand = updateCommand;
    
        }
    }
    
    Partial Public Class CustomersSyncAdapter
        Private Sub OnInitialized()
    
            ' Redefine the insert command so that it does not insert values 
            ' into the CreationDate and LastEditDate columns.
            Dim insertCommand As New System.Data.SqlClient.SqlCommand
            With insertCommand
                .CommandText = "INSERT INTO dbo.Customers ([CustomerID], [CompanyName], " & _
                    "[ContactName], [ContactTitle], [Address], [City], [Region], [PostalCode], " & _
                    "[Country], [Phone], [Fax] )" & _
                    "VALUES (@CustomerID, @CompanyName, @ContactName, @ContactTitle, @Address, @City, " & _
                    "@Region, @PostalCode, @Country, @Phone, @Fax) SET @sync_row_count = @@rowcount"
                .CommandType = System.Data.CommandType.Text
                .Parameters.Add("@CustomerID", System.Data.SqlDbType.NChar)
                .Parameters.Add("@CompanyName", System.Data.SqlDbType.NVarChar)
                .Parameters.Add("@ContactName", System.Data.SqlDbType.NVarChar)
                .Parameters.Add("@ContactTitle", System.Data.SqlDbType.NVarChar)
                .Parameters.Add("@Address", System.Data.SqlDbType.NVarChar)
                .Parameters.Add("@City", System.Data.SqlDbType.NVarChar)
                .Parameters.Add("@Region", System.Data.SqlDbType.NVarChar)
                .Parameters.Add("@PostalCode", System.Data.SqlDbType.NVarChar)
                .Parameters.Add("@Country", System.Data.SqlDbType.NVarChar)
                .Parameters.Add("@Phone", System.Data.SqlDbType.NVarChar)
                .Parameters.Add("@Fax", System.Data.SqlDbType.NVarChar)
                .Parameters.Add("@sync_row_count", System.Data.SqlDbType.Int)
                .Parameters("@sync_row_count").Direction = ParameterDirection.Output
            End With
    
            Me.InsertCommand = insertCommand
    
    
            ' Redefine the update command so that it does not update values 
            ' in the CreationDate and LastEditDate columns.
            Dim updateCommand As New System.Data.SqlClient.SqlCommand
            With updateCommand
                .CommandText = "UPDATE dbo.Customers SET [CompanyName] = @CompanyName, [ContactName] " & _
                    "= @ContactName, [ContactTitle] = @ContactTitle, [Address] = @Address, [City] " & _
                    "= @City, [Region] = @Region, [PostalCode] = @PostalCode, [Country] = @Country, " & _
                    "[Phone] = @Phone, [Fax] = @Fax " & _
                    "WHERE ([CustomerID] = @CustomerID) AND (@sync_force_write = 1 " & _
                    "OR ([LastEditDate] <= @sync_last_received_anchor)) SET @sync_row_count = @@rowcount"
                .CommandType = System.Data.CommandType.Text
                .Parameters.Add("@CompanyName", System.Data.SqlDbType.NVarChar)
                .Parameters.Add("@ContactName", System.Data.SqlDbType.NVarChar)
                .Parameters.Add("@ContactTitle", System.Data.SqlDbType.NVarChar)
                .Parameters.Add("@Address", System.Data.SqlDbType.NVarChar)
                .Parameters.Add("@City", System.Data.SqlDbType.NVarChar)
                .Parameters.Add("@Region", System.Data.SqlDbType.NVarChar)
                .Parameters.Add("@PostalCode", System.Data.SqlDbType.NVarChar)
                .Parameters.Add("@Country", System.Data.SqlDbType.NVarChar)
                .Parameters.Add("@Phone", System.Data.SqlDbType.NVarChar)
                .Parameters.Add("@Fax", System.Data.SqlDbType.NVarChar)
                .Parameters.Add("@CustomerID", System.Data.SqlDbType.NChar)
                .Parameters.Add("@sync_force_write", System.Data.SqlDbType.Bit)
                .Parameters.Add("@sync_last_received_anchor", System.Data.SqlDbType.DateTime)
                .Parameters.Add("@sync_row_count", System.Data.SqlDbType.Int)
                .Parameters("@sync_row_count").Direction = ParameterDirection.Output
            End With
    
            Me.UpdateCommand = updateCommand
    
        End Sub
    
    End Class
    

測試應用程式

若要同步處理並檢視追蹤資料行更新

  1. 按 F5。

  2. 變更 LastEditDate 資料行中的值,然後按一下 [儲存] 按鈕,更新表單中的一項記錄。

  3. 返回至表單並按一下 [開始同步處理]。

  4. 驗證在應用程式方格中與伺服器資料庫中的更新資料。 請注意,伺服器上資料行中的值,已覆寫用戶端上的更新。 更新程序如下所示:

    1. Synchronization Services 會判斷用戶端上有一個資料列受到變更。

    2. 在同步處理期間會上載這個資料列,並套用至伺服器資料庫中的資料表。 然而,追蹤資料行並不包含在更新陳述式中。 Synchronization Services 實際上對資料表執行的是「假更新」。

    3. 資料列接著會回應至用戶端,但由伺服器選取變更的命令有包含追蹤資料行。 因此,在用戶端所做的變更會由伺服器上的值覆寫。

後續步驟

在本逐步解說中,您以基本衝突處理設定了雙向同步處理,並處理了在用戶端資料庫中使用伺服器追蹤資料行的可能問題。 藉著使用部分類別,您還可以在其他重要的面向上擴充 [本機資料庫快取] 程式碼。 例如,您可以重新定義由伺服器資料庫選取變更的 SQL 命令,讓資料在下載至用戶端時先篩選。 我們建議您閱讀本文件中的 HOW TO 主題,了解您可以加入或變更同步處理程式碼的方式,以符合您應用程式的需求。 如需詳細資訊,請參閱如何設計一般用戶端和伺服器同步處理工作的程式 (英文)。

請參閱

概念

偶爾連接的應用程式概觀

其他資源

撰寫一般用戶端和伺服器同步處理工作

協助您開發應用程式的工具 (Synchronization Services)