如何:以非同步方式同步處理資料 (以程式設計的方式)
在此主題中,您將學習如何使用 SqlCeReplication 類別,以非同步方式同步處理訂閱。非同步的資料同步處理可讓您的應用程式能在同步處理期間執行其他動作。如需使用 SqlServerCe 命名空間的詳細資訊,請參閱 SqlServerCe 命名空間的參考說明文件。
若要啟動非同步的資料同步處理
初始化 SqlCeReplication 物件。您必須在所有方法之外宣告物件,以便能夠存取該物件。
private SqlCeReplication repl;
在開始同步處理的方法中,建立 SqlCeReplication 物件的執行個體,然後設定與發行者進行同步處理所需的屬性。
this.repl = new SqlCeReplication(); repl.InternetUrl = "https://www.adventure-works.com/sqlmobile/sqlcesa35.dll"; repl.InternetLogin = "MyInternetLogin"; repl.InternetPassword = "<password>"; repl.Publisher = "MyPublisher"; repl.PublisherDatabase = "MyPublisherDatabase"; repl.PublisherLogin = "MyPublisherLogin"; repl.PublisherPassword = "<password>"; repl.Publication = "MyPublication"; repl.Subscriber = "MySubscriber"; repl.SubscriberConnectionString = "Data Source=MyDatabase.sdf";
呼叫 BeginSynchronize 方法。這會傳回 IAsyncResult 物件。當您呼叫 BeginSynchronize 時,必須傳入 AsyncCallback 事件處理常式及 SqlCeReplication 物件。完成同步處理時,便會引發 AsyncCallback 事件。您也可傳入 OnStartTableUpload、OnStartTableDownload 和 OnSynchronization 事件的事件處理常式。
IAsyncResult ar = repl.BeginSynchronize (new syncCallback(this.SyncCompletedCallback), new OnStartTableUpload(this.OnStartTableUploadCallback), new OnStartTableDownload(this.OnStartTableDownloadCallback), new OnSynchronization(this.OnSynchronizationCallback), repl);
處理同步處理事件:
唯一需要的事件是 AsyncCallback,這個事件以 IAsyncResult 做為其唯一的參數。
public void SyncCompletedCallback(IAsyncResult ar) { ... }
OnStartTableUpload 及 OnStartTableDownload 事件處理常式都以 IAsyncResult 及資料表名稱 (字串型態) 做為參數。
public void OnStartTableUploadCallback(IAsyncResult ar, string tableName) { ... } public void OnStartTableDownloadCallback(IAsyncResult ar,string tableName) { ... }
OnSynchronization 事件處理常式以 IAsyncResult 和代表同步處理已完成百分比的整數做為參數。
public void OnSynchronizationCallback(IAsyncResult ar, int percentComplete) { ... }
若要結束非同步的資料同步處理
在 AsyncCallback 事件處理常式中,使用傳入的 SqlCeReplication 物件和 IAsyncResult 物件,呼叫 EndSynchronize 方法。
SqlCeReplication repl = (SqlCeReplication)ar.AsyncState; repl.EndSynchronize(ar);
範例
本範例顯示如何實作非同步的資料同步處理。在此範例中,應用程式於同步處理期間使用 SyncStatus 更新使用者介面,以便使用者瞭解進度。每當同步處理事件引發,以及每次上載和下載資料表時,便會更新使用者介面。同步處理完成之後,應用程式就會從 __sysMergeSubscriptions 資料表取得最近一次同步處理成功的時間並顯示結果。
public class MyForm : Form
{
private string tableName;
private int percentage;
private SyncStatus eventStatus;
private SqlCeReplication repl;
private EventHandler myUserInterfaceUpdateEvent;
internal enum SyncStatus
{
PercentComplete,
BeginUpload,
BeginDownload,
SyncComplete
}
public MyForm()
{
// InitializeComponent();
this.myUserInterfaceUpdateEvent = new EventHandler(MyUserInterfaceUpdateEvent);
}
public void MyUserInterfaceUpdateEvent(object sender, System.EventArgs e)
{
switch (this.eventStatus)
{
case SyncStatus.BeginUpload:
//this.labelStatusValue.Text = "Began uploading table : " + tableName;
break;
case SyncStatus.PercentComplete:
//this.labelStatusValue.Text = "Sync with SQL Server is " + percentage.ToString() + "% complete.";
break;
case SyncStatus.BeginDownload:
//this.labelStatusValue.Text = "Began downloading table : " + tableName;
break;
case SyncStatus.SyncComplete:
//this.labelStatusValue.Text = "Synchronization has completed successfully";
//this.labelLastSyncValue.Text = GetLastSuccessfulSyncTime().ToString();
break;
}
}
public void SyncCompletedCallback(IAsyncResult ar)
{
try
{
SqlCeReplication repl = (SqlCeReplication)ar.AsyncState;
repl.EndSynchronize(ar);
repl.SaveProperties();
this.eventStatus = SyncStatus.SyncComplete;
}
catch (SqlCeException e)
{
MessageBox.Show(e.Message);
}
finally
{
// NOTE: If you want to set Control properties from within this
// method, you must use Control.Invoke method to marshal
// the call to the UI thread; otherwise you might deadlock your
// application; See Control.Invoke documentation for more information
//
this.Invoke(this.myUserInterfaceUpdateEvent);
}
}
public void OnStartTableUploadCallback(IAsyncResult ar, string tableName)
{
this.tableName = tableName;
this.eventStatus = SyncStatus.BeginUpload;
// NOTE: If you want to set Control properties from within this
// method, you must use Control.Invoke method to marshal
// the call to the UI thread; otherwise you might deadlock your
// application; See Control.Invoke documentation for more information
//
this.Invoke(this.myUserInterfaceUpdateEvent);
}
public void OnSynchronizationCallback(IAsyncResult ar, int percentComplete)
{
this.percentage = percentComplete;
this.eventStatus = SyncStatus.PercentComplete;
// NOTE: If you want to set Control properties from within this
// method, you must use Control.Invoke method to marshal
// the call to the UI thread; otherwise you might deadlock your
// application; See Control.Invoke documentation for more information
//
this.Invoke(this.myUserInterfaceUpdateEvent);
}
public void OnStartTableDownloadCallback(IAsyncResult ar, string tableName)
{
this.tableName = tableName;
this.eventStatus = SyncStatus.BeginDownload;
// NOTE: If you want to set Control properties from within this
// method, you must use Control.Invoke method to marshal
// the call to the UI thread; otherwise you might deadlock your
// application; See Control.Invoke documentation for more information
//
this.Invoke(this.myUserInterfaceUpdateEvent);
}
private void ButtonSynchronize_Click(object sender, System.EventArgs e)
{
try
{
this.repl = new SqlCeReplication();
repl.SubscriberConnectionString = "Data Source=Test.sdf";
if (false == File.Exists("Test.sdf"))
{
repl.AddSubscription(AddOption.CreateDatabase);
repl.PublisherSecurityMode = SecurityType.DBAuthentication;
repl.Publisher = "MyPublisher";
repl.PublisherLogin = "PublisherLogin";
repl.PublisherPassword = "<Password>";
repl.PublisherDatabase = "AdventureWorksDW";
repl.Publication = "AdventureWorksDW";
repl.InternetUrl = "https://www.adventure-works.com/sqlmobile/sqlcesa35.dll";
repl.InternetLogin = "MyInternetLogin";
repl.InternetPassword = "<Password";
repl.Subscriber = "MySubscriber";
}
else
{
repl.LoadProperties();
}
IAsyncResult ar = repl.BeginSynchronize(
new AsyncCallback(this.SyncCompletedCallback),
new OnStartTableUpload(this.OnStartTableUploadCallback),
new OnStartTableDownload(this.OnStartTableDownloadCallback),
new OnSynchronization(this.OnSynchronizationCallback),
repl);
}
catch (SqlCeException ex)
{
MessageBox.Show(ex.Message);
}
}
public DateTime GetLastSuccessfulSyncTime()
{
DateTime localDateTime;
SqlCeConnection conn = null;
SqlCeCommand cmd = null;
try
{
conn = new SqlCeConnection("Data Source = Test.sdf");
conn.Open();
cmd = conn.CreateCommand();
cmd.CommandText = "SELECT LastSuccessfulSync FROM __sysMergeSubscriptions " +
"WHERE Publication=@publication";
cmd.Parameters.Add("@publication", SqlDbType.NVarChar, 4000);
cmd.Parameters["@publication"].Value = "AdventureWorksDW";
//Note: LastSuccessfulSync is stored in local time, not UTC time
localDateTime = (DateTime)cmd.ExecuteScalar();
return localDateTime;
}
finally
{
conn.Close();
}
}
}
Public Class MyForm
Inherits Form
Private myUserInterfaceUpdateEvent As EventHandler
Private tableName As String
Private percentage As Integer
Private eventStatus As SyncStatus
Private repl As SqlCeReplication
Friend Enum SyncStatus
PercentComplete
BeginUpload
BeginDownload
SyncComplete
End Enum 'SyncStatus
Public Sub New()
' InitializeComponent();
Me.myUserInterfaceUpdateEvent = New EventHandler(AddressOf UserInterfaceUpdateEvent)
End Sub 'New
Public Sub UserInterfaceUpdateEvent(ByVal sender As Object, ByVal e As System.EventArgs)
Select Case Me.eventStatus
Case SyncStatus.BeginUpload
'this.labelStatusValue.Text = "Began uploading table : " & tableName;
Case SyncStatus.PercentComplete
'this.labelStatusValue.Text = "Sync with SQL Server is " & percentage.ToString() & "% complete.";
Case SyncStatus.BeginDownload
'this.labelStatusValue.Text = "Began downloading table : " & tableName;
Case SyncStatus.SyncComplete
'this.labelStatusValue.Text = "Synchronization has completed successfully";
'this.labelLastSyncValue.Text = GetLastSuccessfulSyncTime().ToString();
End Select
End Sub 'UserInterfaceUpdateEvent
Public Sub SyncCompletedCallback(ByVal ar As IAsyncResult)
Try
Dim repl As SqlCeReplication = CType(ar.AsyncState, SqlCeReplication)
repl.EndSynchronize(ar)
repl.SaveProperties()
Me.eventStatus = SyncStatus.SyncComplete
Catch e As SqlCeException
MessageBox.Show(e.Message)
Finally
' NOTE: If you want to set Control properties from within this
' method, you must use Control.Invoke method to marshal
' the call to the UI thread; otherwise you might deadlock your
' application; See Control.Invoke documentation for more information
'
Me.Invoke(Me.myUserInterfaceUpdateEvent)
End Try
End Sub 'SyncCompletedCallback
Public Sub OnStartTableUploadCallback(ByVal ar As IAsyncResult, ByVal tableName As String)
Me.tableName = tableName
Me.eventStatus = SyncStatus.BeginUpload
' NOTE: If you want to set Control properties from within this
' method, you must use Control.Invoke method to marshal
' the call to the UI thread; otherwise you might deadlock your
' application; See Control.Invoke documentation for more information
'
Me.Invoke(Me.myUserInterfaceUpdateEvent)
End Sub 'OnStartTableUploadCallback
Public Sub OnSynchronizationCallback(ByVal ar As IAsyncResult, ByVal percentComplete As Integer)
Me.percentage = percentComplete
Me.eventStatus = SyncStatus.PercentComplete
' NOTE: If you want to set Control properties from within this
' method, you must use Control.Invoke method to marshal
' the call to the UI thread; otherwise you might deadlock your
' application; See Control.Invoke documentation for more information
'
Me.Invoke(Me.myUserInterfaceUpdateEvent)
End Sub 'OnSynchronizationCallback
Public Sub OnStartTableDownloadCallback(ByVal ar As IAsyncResult, ByVal tableName As String)
Me.tableName = tableName
Me.eventStatus = SyncStatus.BeginDownload
' NOTE: If you want to set Control properties from within this
' method, you must use Control.Invoke method to marshal
' the call to the UI thread; otherwise you might deadlock your
' application; See Control.Invoke documentation for more information
'
Me.Invoke(Me.myUserInterfaceUpdateEvent)
End Sub 'OnStartTableDownloadCallback
Private Sub ButtonSynchronize_Click(ByVal sender As Object, ByVal e As System.EventArgs)
Try
Me.repl = New SqlCeReplication()
repl.SubscriberConnectionString = "Data Source=Test.sdf"
If False = File.Exists("Test.sdf") Then
repl.AddSubscription(AddOption.CreateDatabase)
repl.PublisherSecurityMode = SecurityType.DBAuthentication
repl.Publisher = "MyPublisher"
repl.PublisherLogin = "PublisherLogin"
repl.PublisherPassword = "<Password>"
repl.PublisherDatabase = "AdventureWorksDW"
repl.Publication = "AdventureWorksDW"
repl.InternetUrl = "https://www.adventure-works.com/sqlmobile/sqlcesa35.dll"
repl.InternetLogin = "InternetLogin"
repl.InternetPassword = "<Password>"
repl.Subscriber = "MySubscriber"
Else
repl.LoadProperties()
End If
Dim ar As IAsyncResult = repl.BeginSynchronize( _
New AsyncCallback(AddressOf Me.SyncCompletedCallback), _
New OnStartTableUpload(AddressOf Me.OnStartTableUploadCallback), _
New OnStartTableDownload(AddressOf Me.OnStartTableDownloadCallback), _
New OnSynchronization(AddressOf Me.OnSynchronizationCallback), repl)
Catch ex As SqlCeException
MessageBox.Show(ex.Message)
End Try
End Sub 'ButtonSynchronize_Click
Public Function GetLastSuccessfulSyncTime() As DateTime
Dim localDateTime As DateTime
Dim conn As SqlCeConnection = Nothing
Dim cmd As SqlCeCommand = Nothing
Try
conn = New SqlCeConnection("Data Source = Test.sdf")
conn.Open()
cmd = conn.CreateCommand()
cmd.CommandText = "SELECT LastSuccessfulSync FROM __sysMergeSubscriptions " & _
"WHERE Publication=@publication"
cmd.Parameters.Add("@publication", SqlDbType.NVarChar, 4000)
cmd.Parameters("@publication").Value = "AdventureWorksDW"
'Note: LastSuccessfulSync is stored in local time, not UTC time
localDateTime = CType(cmd.ExecuteScalar(), DateTime)
Return localDateTime
Finally
conn.Close()
End Try
End Function 'GetLastSuccessfulSyncTime
End Class 'MyForm