Vorgehensweise: Angeben der Reihenfolge und der Batchgröße von Änderungen
In diesem Thema wird erläutert, wie Sie die Reihenfolge und die Batchgröße von Änderungen angeben können, die mit Sync Framework in eine Clientdatenbank heruntergeladen werden. Die Beispiele in diesem Thema beziehen sich auf die folgenden Sync Framework-Typen und -Ereignisse:
Informationen dazu, wie Sie Beispielcode ausführen können, finden Sie unter "Beispielanwendungen in den Themen zur Vorgehensweise" in Programmieren von allgemeinen Client- und Serversynchronisierungsaufgaben.
Reihenfolge und Batchverarbeitung bei der Synchronisierung
Für jede Tabelle, die synchronisiert werden soll, werden Änderungen in der Serverdatenbank in der folgenden Reihenfolge ausgewählt: Einfügungen, Aktualisierungen, Löschvorgänge. Die Übernahme von Änderungen in die Clientdatenbank erfolgt in der folgenden Reihenfolge: Löschvorgänge, Einfügungen, Aktualisierungen. Wenn mehrere Tabellen synchronisiert werden, richtet sich die Reihenfolge der Verarbeitung der einzelnen Tabellen nach der Reihenfolge, in der dessen SyncTable-Objekt der Auflistung der Tabellen für den Synchronisierungs-Agent hinzugefügt wurde. Wenn z. B. die Tabellen Customer und OrderHeader in dieser Reihenfolge hinzugefügt werden, werden zuerst die Einfügungen in der Customer-Tabelle und dann die darin vorhandenen Aktualisierungen und Löschvorgänge ausgewählt. Anschließend werden die Änderungen in der OrderHeader-Tabelle ausgewählt. Sämtliche Änderungen an der Customer-Tabelle werden in einer einzelnen Transaktion in die Clientdatenbank übernommen (sofern keine Batchverarbeitung erfolgt), in einer zweiten Transaktion werden dann die Änderungen an der OrderHeader-Tabelle übernommen. Wenn die Tabellen Customer und OrderHeader demselben SyncGroup-Objekt zugewiesen werden, werden die Einfügungen, Aktualisierungen und Löschvorgänge für beide Tabellen einmal ausgewählt. Sämtliche Änderungen werden dann in einer gemeinsamen Transaktion in die Clientdatenbank übernommen (sofern auch dabei keine Batchverarbeitung erfolgt).
Standardmäßig unterteilt Sync Framework Änderungen nicht in Batches. Änderungen werden als eine Einheit in die Clientdatenbank heruntergeladen und von dort hochgeladen. Bei vielen Anwendungen bietet es sich aber an, Änderungen in kleinere Batches aufzuteilen. Wenn z. B. eine Synchronisierungssitzung abgebrochen wird, kann die Synchronisierung beim letzten Batch wieder aufgenommen werden, und es müssen nicht alle Änderungen erneut gesendet werden. Eine Unterteilung in Batches kann sich auch positiv auf die Leistung auswirken, da der Client einen kleineren Batch Änderungen gleichzeitig verwalten kann. Aufgrund dieser Vorteile ist es in Sync Framework möglich, dass Anwendungen Änderungen in Batches auf den Client herunterladen (beim Hochladen wird die Batchverarbeitung nicht unterstützt).
Die Batchverarbeitung kann durch Festlegen eines Werts für die BatchSize-Eigenschaft und durch Erstellen eines Befehls für die SelectNewAnchorCommand-Eigenschaft aktiviert werden, der für jeden Änderungsbatch Ankerwerte zurückgeben kann. Wenn keine Batchverarbeitung erfolgt, verwenden Anwendungen den jeweils neuen und letzten Ankerwert, um die obere und die untere Grenze des Satzes von Änderungen zu bestimmen, die heruntergeladen werden sollen. Weitere Informationen finden Sie unter Erste Schritte: Client- und Serversynchronisierung. Bei der Batchverarbeitung definiert der Maximal-empfangen-Ankerwert die obere Grenze für den gesamten Satz von Änderungen, und der neue und der letzte Ankerwert definieren die obere und die untere Grenze für den jeweiligen Batch von Änderungen. Das SessionProgress-Ereignis stellt eine bequeme Möglichkeit dar, den Gesamtfortschritt der Synchronisierung zu überwachen, und das BatchProgress-Ereignis bietet Zugriff auf Angaben zum Fortschritt auf der Batchebene.
Beispiel
In den folgenden Codebeispielen wird gezeigt, wie die Tabellen Customer
und OrderHeader
in der Sync Framework-Beispieldatenbank synchronisiert werden können. Die Änderungen für diese Tabellen werden in Batches heruntergeladen, wobei jeder Batch 50 Änderungen enthält. Bei der Erstsynchronisierung werden 10 Zeilen heruntergeladen. Alle Zeilen werden in einem gemeinsamen Batch heruntergeladen und in einer gemeinsamen Transaktion übernommen. Bei der folgenden Synchronisierung werden 92 Zeilen in zwei Batches heruntergeladen. Jeder Batch enthält Änderungen aus der Customer
-Tabelle und der OrderHeader
-Tabelle, und jeder Batch wird in einer gemeinsamen Transaktion übernommen.
Schlüsselbestandteile der API
In diesem Abschnitt finden Sie Codebeispiele, die die Schlüsselbestandteile der API herausstellen, die zum Festlegen der Reihenfolge und für die Batchverarbeitung von Änderungen verwendet werden. Das folgende Codebeispiel stammt aus einer Klasse, die von der SyncAgent-Klasse abgeleitet ist. Der Code erstellt ein SyncGroup-Objekt für die Tabellen Customer
und OrderHeader
.
//Create a SyncGroup so that changes to Customer
//and OrderHeader are made in one transaction.
SyncGroup customerOrderSyncGroup = new SyncGroup("CustomerOrder");
//Add each table: specify a synchronization direction of
//DownloadOnly.
SyncTable customerSyncTable = new SyncTable("Customer");
customerSyncTable.CreationOption = TableCreationOption.DropExistingOrCreateNewTable;
customerSyncTable.SyncDirection = SyncDirection.DownloadOnly;
customerSyncTable.SyncGroup = customerOrderSyncGroup;
this.Configuration.SyncTables.Add(customerSyncTable);
SyncTable orderHeaderSyncTable = new SyncTable("OrderHeader");
orderHeaderSyncTable.CreationOption = TableCreationOption.DropExistingOrCreateNewTable;
orderHeaderSyncTable.SyncDirection = SyncDirection.DownloadOnly;
orderHeaderSyncTable.SyncGroup = customerOrderSyncGroup;
this.Configuration.SyncTables.Add(orderHeaderSyncTable);
'Create a SyncGroup so that changes to Customer
'and OrderHeader are made in one transaction.
Dim customerOrderSyncGroup As New SyncGroup("CustomerOrder")
'Add each table: specify a synchronization direction of
'DownloadOnly.
Dim customerSyncTable As New SyncTable("Customer")
customerSyncTable.CreationOption = TableCreationOption.DropExistingOrCreateNewTable
customerSyncTable.SyncDirection = SyncDirection.DownloadOnly
customerSyncTable.SyncGroup = customerOrderSyncGroup
Me.Configuration.SyncTables.Add(customerSyncTable)
Dim orderHeaderSyncTable As New SyncTable("OrderHeader")
orderHeaderSyncTable.CreationOption = TableCreationOption.DropExistingOrCreateNewTable
orderHeaderSyncTable.SyncDirection = SyncDirection.DownloadOnly
orderHeaderSyncTable.SyncGroup = customerOrderSyncGroup
Me.Configuration.SyncTables.Add(orderHeaderSyncTable)
Das folgende Codebeispiel stammt aus einer Klasse, die von der DbServerSyncProvider-Klasse abgeleitet ist. Der Code erstellt einen Ankerbefehl für eine Anwendung, die keine Batchverarbeitung verwendet. Er gibt für den gesamten zu synchronisierenden Änderungssatz einen einzigen neuen Ankerwert zurück. Dieses Beispiel soll den Unterschied zwischen einem Befehl, der Batchverarbeitung verwendet, und einem Befehl verdeutlichen, der keine Batchverarbeitung verwendet.
SqlCommand selectNewAnchorCommand = new SqlCommand();
string newAnchorVariable = "@" + SyncSession.SyncNewReceivedAnchor;
selectNewAnchorCommand.CommandText = "SELECT " + newAnchorVariable + " = min_active_rowversion() - 1";
selectNewAnchorCommand.Parameters.Add(newAnchorVariable, SqlDbType.Timestamp);
selectNewAnchorCommand.Parameters[newAnchorVariable].Direction = ParameterDirection.Output;
selectNewAnchorCommand.Connection = serverConn;
this.SelectNewAnchorCommand = selectNewAnchorCommand;
Dim selectNewAnchorCommand As New SqlCommand()
Dim newAnchorVariable As String = "@" + SyncSession.SyncNewReceivedAnchor
selectNewAnchorCommand.CommandText = "SELECT " + newAnchorVariable + " = min_active_rowversion() - 1"
selectNewAnchorCommand.Parameters.Add(newAnchorVariable, SqlDbType.Timestamp)
selectNewAnchorCommand.Parameters(newAnchorVariable).Direction = ParameterDirection.Output
selectNewAnchorCommand.Connection = serverConn
Me.SelectNewAnchorCommand = selectNewAnchorCommand
Der folgende Code erstellt einen Ankerbefehl, der verwendet werden kann, wenn Änderungen in Batches geliefert werden. Statt einen einzigen neuen Ankerwert für den gesamten Änderungssatz zurückzugeben, gibt er für jeden Batch von Änderungen einen separaten neuen Ankerwert zurück. Der Code verwendet die BatchSize-Eigenschaft, um anzugeben, wie viele Änderungen in jedem Batch enthalten sein sollen, und Sitzungsvariablen, um Ankerwerte zwischen einer gespeicherten Prozedur und der Synchronisierungslaufzeit hin und her zu geben. Wenn Sie Synchronisierungsadapterbefehle manuell schreiben, verwenden Sie ebenfalls die Sitzungsvariablen @sync_new_received_anchor und @sync_last_received_anchor. Die @sync_max_received_anchor-Sitzungsvariable wird nur vom neuen Ankerbefehl verwendet.
SqlCommand selectNewAnchorCommand = new SqlCommand();
selectNewAnchorCommand.Connection = serverConn;
selectNewAnchorCommand.CommandText = "usp_GetNewBatchAnchor";
selectNewAnchorCommand.CommandType = CommandType.StoredProcedure;
selectNewAnchorCommand.Parameters.Add("@" + SyncSession.SyncLastReceivedAnchor, SqlDbType.Timestamp, 8);
selectNewAnchorCommand.Parameters.Add("@" + SyncSession.SyncMaxReceivedAnchor, SqlDbType.Timestamp, 8);
selectNewAnchorCommand.Parameters.Add("@" + SyncSession.SyncNewReceivedAnchor, SqlDbType.Timestamp, 8);
selectNewAnchorCommand.Parameters.Add("@" + SyncSession.SyncBatchSize, SqlDbType.Int, 4);
selectNewAnchorCommand.Parameters.Add("@" + SyncSession.SyncBatchCount, SqlDbType.Int, 4);
selectNewAnchorCommand.Parameters["@" + SyncSession.SyncMaxReceivedAnchor].Direction = ParameterDirection.Output;
selectNewAnchorCommand.Parameters["@" + SyncSession.SyncNewReceivedAnchor].Direction = ParameterDirection.Output;
selectNewAnchorCommand.Parameters["@" + SyncSession.SyncBatchCount].Direction = ParameterDirection.InputOutput;
this.SelectNewAnchorCommand = selectNewAnchorCommand;
this.BatchSize = 50;
Dim selectNewAnchorCommand As New SqlCommand()
selectNewAnchorCommand.Connection = serverConn
selectNewAnchorCommand.CommandText = "usp_GetNewBatchAnchor"
selectNewAnchorCommand.CommandType = CommandType.StoredProcedure
selectNewAnchorCommand.Parameters.Add("@" + SyncSession.SyncLastReceivedAnchor, SqlDbType.Timestamp, 8)
selectNewAnchorCommand.Parameters.Add("@" + SyncSession.SyncMaxReceivedAnchor, SqlDbType.Timestamp, 8)
selectNewAnchorCommand.Parameters.Add("@" + SyncSession.SyncNewReceivedAnchor, SqlDbType.Timestamp, 8)
selectNewAnchorCommand.Parameters.Add("@" + SyncSession.SyncBatchSize, SqlDbType.Int, 4)
selectNewAnchorCommand.Parameters.Add("@" + SyncSession.SyncBatchCount, SqlDbType.Int, 4)
selectNewAnchorCommand.Parameters("@" + SyncSession.SyncMaxReceivedAnchor).Direction = ParameterDirection.Output
selectNewAnchorCommand.Parameters("@" + SyncSession.SyncNewReceivedAnchor).Direction = ParameterDirection.Output
selectNewAnchorCommand.Parameters("@" + SyncSession.SyncBatchCount).Direction = ParameterDirection.InputOutput
Me.SelectNewAnchorCommand = selectNewAnchorCommand
Me.BatchSize = 50
Im folgenden Codebeispiel wird eine gespeicherte Prozedur erstellt, die neue Ankerwerte, einen maximalen Ankerwert und die aktuelle Batchanzahl für Einfügungen und Aktualisierungen ausgibt. Die Prozedur ermöglicht es dem Serversynchronisierungsanbieter, Änderungsbatches aus der Serverdatenbank auszuwählen. Die Logik in dieser gespeicherten Prozedur ist ein Beispiel, es kann aber auch jede andere Logik verwendet werden, sofern diese die hier gezeigten Ausgabewerte bereitstellt. Ein Nachteil des Beispielcodes besteht darin, dass es zu leeren Batches kommen kann, wenn eine Zeile zwischen zwei Synchronisierungen mehr als 50-mal geändert wurde. In einem solchen Fall können Sie Logik hinzufügen.
CREATE PROCEDURE usp_GetNewBatchAnchor (
@sync_last_received_anchor timestamp,
@sync_batch_size bigint,
@sync_max_received_anchor timestamp out,
@sync_new_received_anchor timestamp out,
@sync_batch_count int output)
AS
-- Set a default batch size if a valid one is not passed in.
IF @sync_batch_size IS NULL OR @sync_batch_size <= 0
SET @sync_batch_size = 1000
-- Before selecting the first batch of changes,
-- set the maximum anchor value for this synchronization session.
-- After the first time that this procedure is called,
-- Sync Framework passes a value for @sync_max_received_anchor
-- to the procedure. Batches of changes are synchronized until this
-- value is reached.
IF @sync_max_received_anchor IS NULL
SELECT @sync_max_received_anchor = MIN_ACTIVE_ROWVERSION() - 1
-- If this is the first synchronization session for a database,
-- get the lowest timestamp value from the tables. By default,
-- Sync Framework uses a value of 0 for @sync_last_received_anchor
-- on the first synchronization. If you do not set @sync_last_received_anchor,
-- this can cause empty batches to be downloaded until the lowest
-- timestamp value is reached.
IF @sync_last_received_anchor IS NULL OR @sync_last_received_anchor = 0
BEGIN
SELECT @sync_last_received_anchor = MIN(TimestampCol) FROM (
SELECT MIN(UpdateTimestamp) AS TimestampCol FROM Sales.Customer
UNION
SELECT MIN(InsertTimestamp) AS TimestampCol FROM Sales.Customer
UNION
SELECT MIN(UpdateTimestamp) AS TimestampCol FROM Sales.OrderHeader
UNION
SELECT MIN(InsertTimestamp) AS TimestampCol FROM Sales.OrderHeader
) MinTimestamp
SET @sync_new_received_anchor = @sync_last_received_anchor + @sync_batch_size
-- Determine how many batches are required during the initial synchronization.
IF @sync_batch_count <= 0
SET @sync_batch_count = ((@sync_max_received_anchor / @sync_batch_size) - (@sync_last_received_anchor / @sync_batch_size))
END
ELSE
BEGIN
SET @sync_new_received_anchor = @sync_last_received_anchor + @sync_batch_size
-- Determine how many batches are required during subsequent synchronizations.
IF @sync_batch_count <= 0
SET @sync_batch_count = ((@sync_max_received_anchor / @sync_batch_size) - (@sync_new_received_anchor / @sync_batch_size)) + 1
END
-- Check whether this is the last batch.
IF @sync_new_received_anchor >= @sync_max_received_anchor
BEGIN
SET @sync_new_received_anchor = @sync_max_received_anchor
IF @sync_batch_count <= 0
SET @sync_batch_count = 1
END
GO
Vollständiges Codebeispiel
Das folgende vollständige Codebeispiel enthält die Codebeispiele, die weiter oben beschrieben wurden, sowie zusätzlichen Code zum Ausführen der Synchronisierung. Für das Beispiel wird die in 'Utility'-Klasse für Datenbankanbieter - Themen zur Vorgehensweise enthaltene Utility
-Klasse benötigt.
using System;
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.Server;
using Microsoft.Synchronization.Data.SqlServerCe;
namespace Microsoft.Samples.Synchronization
{
class Program
{
static void Main(string[] args)
{
//The SampleStats class handles information from the
//SyncStatistics object that the Synchronize method returns and
//from SyncAgent events.
SampleStats sampleStats = new SampleStats();
//Request a password for the client database, and delete
//and re-create the database. The client synchronization
//provider also enables you to create the client database
//if it does not exist.
Utility.SetPassword_SqlCeClientSync();
Utility.DeleteAndRecreateCompactDatabase(Utility.ConnStr_SqlCeClientSync, true);
//Initial synchronization. Instantiate the SyncAgent
//and call Synchronize.
SampleSyncAgent sampleSyncAgent = new SampleSyncAgent();
SyncStatistics syncStatistics = sampleSyncAgent.Synchronize();
sampleStats.DisplayStats(syncStatistics, "initial");
//Make changes on the server.
Utility.MakeDataChangesOnServer("CustomerAndOrderHeader");
//Subsequent synchronization.
syncStatistics = sampleSyncAgent.Synchronize();
sampleStats.DisplayStats(syncStatistics, "subsequent");
//Return server data back to its original state.
Utility.CleanUpServer();
//Exit.
Console.Write("\nPress Enter to close the window.");
Console.ReadLine();
}
}
//Create a class that is derived from
//Microsoft.Synchronization.SyncAgent.
public class SampleSyncAgent : SyncAgent
{
public SampleSyncAgent()
{
//Instantiate a client synchronization provider and specify it
//as the local provider for this synchronization agent.
this.LocalProvider = new SampleClientSyncProvider();
//Instantiate a server synchronization provider and specify it
//as the remote provider for this synchronization agent.
this.RemoteProvider = new SampleServerSyncProvider();
//Create a SyncGroup so that changes to Customer
//and OrderHeader are made in one transaction.
SyncGroup customerOrderSyncGroup = new SyncGroup("CustomerOrder");
//Add each table: specify a synchronization direction of
//DownloadOnly.
SyncTable customerSyncTable = new SyncTable("Customer");
customerSyncTable.CreationOption = TableCreationOption.DropExistingOrCreateNewTable;
customerSyncTable.SyncDirection = SyncDirection.DownloadOnly;
customerSyncTable.SyncGroup = customerOrderSyncGroup;
this.Configuration.SyncTables.Add(customerSyncTable);
SyncTable orderHeaderSyncTable = new SyncTable("OrderHeader");
orderHeaderSyncTable.CreationOption = TableCreationOption.DropExistingOrCreateNewTable;
orderHeaderSyncTable.SyncDirection = SyncDirection.DownloadOnly;
orderHeaderSyncTable.SyncGroup = customerOrderSyncGroup;
this.Configuration.SyncTables.Add(orderHeaderSyncTable);
}
}
//Create a class that is derived from
//Microsoft.Synchronization.Server.DbServerSyncProvider.
public class SampleServerSyncProvider : DbServerSyncProvider
{
public SampleServerSyncProvider()
{
//Create a connection to the sample server database.
Utility util = new Utility();
SqlConnection serverConn = new SqlConnection(Utility.ConnStr_DbServerSync);
this.Connection = serverConn;
//Create a command to retrieve a new anchor value from
//the server. In this case, we call a stored procedure
//that returns an anchor that can be used with batches
//of changes.
SqlCommand selectNewAnchorCommand = new SqlCommand();
selectNewAnchorCommand.Connection = serverConn;
selectNewAnchorCommand.CommandText = "usp_GetNewBatchAnchor";
selectNewAnchorCommand.CommandType = CommandType.StoredProcedure;
selectNewAnchorCommand.Parameters.Add("@" + SyncSession.SyncLastReceivedAnchor, SqlDbType.Timestamp, 8);
selectNewAnchorCommand.Parameters.Add("@" + SyncSession.SyncMaxReceivedAnchor, SqlDbType.Timestamp, 8);
selectNewAnchorCommand.Parameters.Add("@" + SyncSession.SyncNewReceivedAnchor, SqlDbType.Timestamp, 8);
selectNewAnchorCommand.Parameters.Add("@" + SyncSession.SyncBatchSize, SqlDbType.Int, 4);
selectNewAnchorCommand.Parameters.Add("@" + SyncSession.SyncBatchCount, SqlDbType.Int, 4);
selectNewAnchorCommand.Parameters["@" + SyncSession.SyncMaxReceivedAnchor].Direction = ParameterDirection.Output;
selectNewAnchorCommand.Parameters["@" + SyncSession.SyncNewReceivedAnchor].Direction = ParameterDirection.Output;
selectNewAnchorCommand.Parameters["@" + SyncSession.SyncBatchCount].Direction = ParameterDirection.InputOutput;
this.SelectNewAnchorCommand = selectNewAnchorCommand;
this.BatchSize = 50;
//Create SyncAdapters for each table by using the SqlSyncAdapterBuilder:
// * Specify the base table and tombstone table names.
// * Specify the columns that are used to track when
// and where changes are made.
// * Specify download only synchronization.
// * Call ToSyncAdapter to create the SyncAdapter.
// * Specify a name for the SyncAdapter that matches the
// the name specified for the corresponding SyncTable.
// Do not include the schema names (Sales in this case).
//Customer table
SqlSyncAdapterBuilder customerBuilder = new SqlSyncAdapterBuilder(serverConn);
customerBuilder.TableName = "Sales.Customer";
customerBuilder.TombstoneTableName = customerBuilder.TableName + "_Tombstone";
customerBuilder.SyncDirection = SyncDirection.DownloadOnly;
customerBuilder.CreationTrackingColumn = "InsertTimestamp";
customerBuilder.UpdateTrackingColumn = "UpdateTimestamp";
customerBuilder.DeletionTrackingColumn = "DeleteTimestamp";
SyncAdapter customerSyncAdapter = customerBuilder.ToSyncAdapter();
customerSyncAdapter.TableName = "Customer";
this.SyncAdapters.Add(customerSyncAdapter);
//OrderHeader table.
SqlSyncAdapterBuilder orderHeaderBuilder = new SqlSyncAdapterBuilder(serverConn);
orderHeaderBuilder.TableName = "Sales.OrderHeader";
orderHeaderBuilder.TombstoneTableName = orderHeaderBuilder.TableName + "_Tombstone";
orderHeaderBuilder.SyncDirection = SyncDirection.DownloadOnly;
orderHeaderBuilder.CreationTrackingColumn = "InsertTimestamp";
orderHeaderBuilder.UpdateTrackingColumn = "UpdateTimestamp";
orderHeaderBuilder.DeletionTrackingColumn = "DeleteTimestamp";
SyncAdapter orderHeaderSyncAdapter = orderHeaderBuilder.ToSyncAdapter();
orderHeaderSyncAdapter.TableName = "OrderHeader";
this.SyncAdapters.Add(orderHeaderSyncAdapter);
//Handle the ChangesSelected event, and display
//information to the console.
this.ChangesSelected += new EventHandler<ChangesSelectedEventArgs>(SampleServerSyncProvider_ChangesSelected);
}
public void SampleServerSyncProvider_ChangesSelected(object sender, ChangesSelectedEventArgs e)
{
Console.WriteLine("Total number of batches: " + e.Context.BatchCount);
Console.WriteLine("Changes applied for group " + e.GroupMetadata.GroupName);
Console.WriteLine("Inserts applied for group: " + e.Context.GroupProgress.TotalInserts.ToString());
Console.WriteLine("Updates applied for group: " + e.Context.GroupProgress.TotalUpdates.ToString());
Console.WriteLine("Deletes applied for group: " + e.Context.GroupProgress.TotalDeletes.ToString());
}
}
//Create a class that is derived from
//Microsoft.Synchronization.Data.SqlServerCe.SqlCeClientSyncProvider.
public class SampleClientSyncProvider : SqlCeClientSyncProvider
{
public SampleClientSyncProvider()
{
//Specify a connection string for the sample client database.
Utility util = new Utility();
this.ConnectionString = Utility.ConnStr_SqlCeClientSync;
}
}
//Handle the statistics that are returned by the SyncAgent.
public class SampleStats
{
public void DisplayStats(SyncStatistics syncStatistics, string syncType)
{
Console.WriteLine(String.Empty);
if (syncType == "initial")
{
Console.WriteLine("****** Initial Synchronization Stats ******");
}
else if (syncType == "subsequent")
{
Console.WriteLine("***** Subsequent Synchronization Stats ****");
}
Console.WriteLine("Start Time: " + syncStatistics.SyncStartTime);
Console.WriteLine("Total Changes Downloaded: " + syncStatistics.TotalChangesDownloaded);
Console.WriteLine("Complete Time: " + syncStatistics.SyncCompleteTime);
Console.WriteLine(String.Empty);
}
}
}
Imports System
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.Server
Imports Microsoft.Synchronization.Data.SqlServerCe
Class Program
Shared Sub Main(ByVal args() As String)
'The SampleStats class handles information from the
'SyncStatistics object that the Synchronize method returns and
'from SyncAgent events.
Dim sampleStats As New SampleStats()
'Request a password for the client database, and delete
'and re-create the database. The client synchronization
'provider also enables you to create the client database
'if it does not exist.
Utility.SetPassword_SqlCeClientSync()
Utility.DeleteAndRecreateCompactDatabase(Utility.ConnStr_SqlCeClientSync, True)
'Initial synchronization. Instantiate the SyncAgent
'and call Synchronize.
Dim sampleSyncAgent As New SampleSyncAgent()
Dim syncStatistics As SyncStatistics = sampleSyncAgent.Synchronize()
sampleStats.DisplayStats(syncStatistics, "initial")
'Make changes on the server.
Utility.MakeDataChangesOnServer("CustomerAndOrderHeader")
'Subsequent synchronization.
syncStatistics = sampleSyncAgent.Synchronize()
sampleStats.DisplayStats(syncStatistics, "subsequent")
'Return server data back to its original state.
Utility.CleanUpServer()
'Exit.
Console.Write(vbLf + "Press Enter to close the window.")
Console.ReadLine()
End Sub 'Main
End Class 'Program
'Create a class that is derived from
'Microsoft.Synchronization.SyncAgent.
Public Class SampleSyncAgent
Inherits SyncAgent
Public Sub New()
'Instantiate a client synchronization provider and specify it
'as the local provider for this synchronization agent.
Me.LocalProvider = New SampleClientSyncProvider()
'Instantiate a server synchronization provider and specify it
'as the remote provider for this synchronization agent.
Me.RemoteProvider = New SampleServerSyncProvider()
'Create a SyncGroup so that changes to Customer
'and OrderHeader are made in one transaction.
Dim customerOrderSyncGroup As New SyncGroup("CustomerOrder")
'Add each table: specify a synchronization direction of
'DownloadOnly.
Dim customerSyncTable As New SyncTable("Customer")
customerSyncTable.CreationOption = TableCreationOption.DropExistingOrCreateNewTable
customerSyncTable.SyncDirection = SyncDirection.DownloadOnly
customerSyncTable.SyncGroup = customerOrderSyncGroup
Me.Configuration.SyncTables.Add(customerSyncTable)
Dim orderHeaderSyncTable As New SyncTable("OrderHeader")
orderHeaderSyncTable.CreationOption = TableCreationOption.DropExistingOrCreateNewTable
orderHeaderSyncTable.SyncDirection = SyncDirection.DownloadOnly
orderHeaderSyncTable.SyncGroup = customerOrderSyncGroup
Me.Configuration.SyncTables.Add(orderHeaderSyncTable)
End Class 'SampleSyncAgent
'Create a class that is derived from
'Microsoft.Synchronization.Server.DbServerSyncProvider.
Public Class SampleServerSyncProvider
Inherits DbServerSyncProvider
Public Sub New()
'Create a connection to the sample server database.
Dim util As New Utility()
Dim serverConn As New SqlConnection(Utility.ConnStr_DbServerSync)
Me.Connection = serverConn
'Create a command to retrieve a new anchor value from
'the server. In this case, we call a stored procedure
'that returns an anchor that can be used with batches
'of changes.
Dim selectNewAnchorCommand As New SqlCommand()
selectNewAnchorCommand.Connection = serverConn
selectNewAnchorCommand.CommandText = "usp_GetNewBatchAnchor"
selectNewAnchorCommand.CommandType = CommandType.StoredProcedure
selectNewAnchorCommand.Parameters.Add("@" + SyncSession.SyncLastReceivedAnchor, SqlDbType.Timestamp, 8)
selectNewAnchorCommand.Parameters.Add("@" + SyncSession.SyncMaxReceivedAnchor, SqlDbType.Timestamp, 8)
selectNewAnchorCommand.Parameters.Add("@" + SyncSession.SyncNewReceivedAnchor, SqlDbType.Timestamp, 8)
selectNewAnchorCommand.Parameters.Add("@" + SyncSession.SyncBatchSize, SqlDbType.Int, 4)
selectNewAnchorCommand.Parameters.Add("@" + SyncSession.SyncBatchCount, SqlDbType.Int, 4)
selectNewAnchorCommand.Parameters("@" + SyncSession.SyncMaxReceivedAnchor).Direction = ParameterDirection.Output
selectNewAnchorCommand.Parameters("@" + SyncSession.SyncNewReceivedAnchor).Direction = ParameterDirection.Output
selectNewAnchorCommand.Parameters("@" + SyncSession.SyncBatchCount).Direction = ParameterDirection.InputOutput
Me.SelectNewAnchorCommand = selectNewAnchorCommand
Me.BatchSize = 50
'Create SyncAdapters for each table by using the SqlSyncAdapterBuilder:
' * Specify the base table and tombstone table names.
' * Specify the columns that are used to track when
' and where changes are made.
' * Specify download only synchronization.
' * Call ToSyncAdapter to create the SyncAdapter.
' * Specify a name for the SyncAdapter that matches the
' the name specified for the corresponding SyncTable.
' Do not include the schema names (Sales in this case).
'Customer table
Dim customerBuilder As New SqlSyncAdapterBuilder(serverConn)
customerBuilder.TableName = "Sales.Customer"
customerBuilder.TombstoneTableName = customerBuilder.TableName + "_Tombstone"
customerBuilder.SyncDirection = SyncDirection.DownloadOnly
customerBuilder.CreationTrackingColumn = "InsertTimestamp"
customerBuilder.UpdateTrackingColumn = "UpdateTimestamp"
customerBuilder.DeletionTrackingColumn = "DeleteTimestamp"
Dim customerSyncAdapter As SyncAdapter = customerBuilder.ToSyncAdapter()
customerSyncAdapter.TableName = "Customer"
Me.SyncAdapters.Add(customerSyncAdapter)
'OrderHeader table.
Dim orderHeaderBuilder As New SqlSyncAdapterBuilder(serverConn)
orderHeaderBuilder.TableName = "Sales.OrderHeader"
orderHeaderBuilder.TombstoneTableName = orderHeaderBuilder.TableName + "_Tombstone"
orderHeaderBuilder.SyncDirection = SyncDirection.DownloadOnly
orderHeaderBuilder.CreationTrackingColumn = "InsertTimestamp"
orderHeaderBuilder.UpdateTrackingColumn = "UpdateTimestamp"
orderHeaderBuilder.DeletionTrackingColumn = "DeleteTimestamp"
Dim orderHeaderSyncAdapter As SyncAdapter = orderHeaderBuilder.ToSyncAdapter()
orderHeaderSyncAdapter.TableName = "OrderHeader"
Me.SyncAdapters.Add(orderHeaderSyncAdapter)
'Handle the ChangesSelected event, and display
'information to the console.
AddHandler Me.ChangesSelected, AddressOf SampleServerSyncProvider_ChangesSelected
End Sub 'New
Public Sub SampleServerSyncProvider_ChangesSelected(ByVal sender As Object, ByVal e As ChangesSelectedEventArgs)
Console.WriteLine("Total number of batches: " & e.Context.BatchCount)
Console.WriteLine("Changes applied for group " & e.GroupMetadata.GroupName)
Console.WriteLine("Inserts applied for group: " & e.Context.GroupProgress.TotalInserts.ToString())
Console.WriteLine("Updates applied for group: " & e.Context.GroupProgress.TotalUpdates.ToString())
Console.WriteLine("Deletes applied for group: " & e.Context.GroupProgress.TotalDeletes.ToString())
End Sub 'SampleServerSyncProvider_ChangesSelected
End Class 'SampleServerSyncProvider
'Create a class that is derived from
'Microsoft.Synchronization.Data.SqlServerCe.SqlCeClientSyncProvider.
Public Class SampleClientSyncProvider
Inherits SqlCeClientSyncProvider
Public Sub New()
'Specify a connection string for the sample client database.
Dim util As New Utility()
Me.ConnectionString = Utility.ConnStr_SqlCeClientSync
End Sub 'New
End Class 'SampleClientSyncProvider
'Handle the statistics that are returned by the SyncAgent.
Public Class SampleStats
Public Sub DisplayStats(ByVal syncStatistics As SyncStatistics, ByVal syncType As String)
Console.WriteLine(String.Empty)
If syncType = "initial" Then
Console.WriteLine("****** Initial Synchronization Stats ******")
ElseIf syncType = "subsequent" Then
Console.WriteLine("***** Subsequent Synchronization Stats ****")
End If
Console.WriteLine("Start Time: " & syncStatistics.SyncStartTime)
Console.WriteLine("Total Changes Downloaded: " & syncStatistics.TotalChangesDownloaded)
Console.WriteLine("Complete Time: " & syncStatistics.SyncCompleteTime)
Console.WriteLine(String.Empty)
End Sub 'DisplayStats
End Class 'SampleStats
Siehe auch
Konzepte
Programmieren von allgemeinen Client- und Serversynchronisierungsaufgaben