방법: 데이터를 비동기적으로 동기화(프로그래밍 방식)
이 항목에서는 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);
동기화 이벤트를 처리하려면 다음과 같이 하십시오.
IAsyncResult를 자신의 유일한 매개 변수로 사용하는 AsyncCallback 이벤트만 필요합니다.
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