Поделиться через


Как синхронизировать данные в асинхронном режиме (программным путем)

В этом разделе объясняется, как синхронизировать подписку в асинхронном режиме с помощью класса SqlCeReplication. Синхронизация данных в асинхронном режиме позволяет приложению выполнять другие действия во время этого процесса. Дополнительные сведения об использовании пространства имен SqlServerCe см. в справочной документации по пространству имен SqlServerCe.

Запуск синхронизации данных в асинхронном режиме

  1. Инициализируйте объект SqlCeReplication. Этот объект необходимо объявить вне метода, чтобы к нему был возможен доступ.

    private SqlCeReplication repl;
    
  2. В методе, запускающем синхронизацию, создайте экземпляр объекта SqlCeReplication и задайте необходимые свойства синхронизации с издателем.

    this.repl = new SqlCeReplication();
    repl.InternetUrl = "https://www.adventure-works.com/sqlmobile/sqlcesa30.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";
    
  3. Вызовите метод BeginSynchronize. Будет возвращен объект IAsyncResult. При вызове метода BeginSynchronize необходимо передать в него обработчик события AsyncCallback и объект SqlCeReplication. По завершении синхронизации инициируется событие AsyncCallback. Можно также передать обработчики событий OnStartTableUpload, OnStartTableDownload и OnSynchronization.

    IAsyncResult ar = repl.BeginSynchronize(new AsyncCallback(this.SyncCompletedCallback), new OnStartTableUpload(this.OnStartTableUploadCallback), new OnStartTableDownload(this.OnStartTableDownloadCallback), new OnSynchronization(this.OnSynchronizationCallback), repl);
    

Обработка событий синхронизации

  1. Единственное обязательное событие — это AsyncCallback, которое принимает IAsyncResult в качестве единственного параметра.

    public void SyncCompletedCallback(IAsyncResult ar)
    { ... }
    
  2. Обработчики событий OnStartTableUpload и OnStartTableDownload принимают в качестве параметров IAsyncResult и имя таблицы (в виде строки).

    public void OnStartTableUploadCallback(IAsyncResult ar, string tableName)
    { ... }
    public void OnStartTableDownloadCallback(IAsyncResult ar, string tableName)
    { ... }
    
  3. Обработчик события OnSynchronization принимает в качестве параметров IAsyncResult и целое число, представляющее степень выполнения синхронизации в процентах.

    public void OnSynchronizationCallback(IAsyncResult ar, int percentComplete)
    { ... }
    

Завершение синхронизации данных в асинхронном режиме

  1. В обработчике события 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/sqlcesa30.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/sqlcesa30.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

См. также

Основные понятия

Асинхронная синхронизация данных
Использование репликации слиянием

Справка и поддержка

Получение помощи по SQL Server Compact Edition