locked
Allow user edit on dbapplychangefailed ? RRS feed

  • Question

  • When a CType(syncOrchestrator.LocalProvider, SqlSyncProvider).ApplyChangeFailed is raised by the syncorchestrator and we have a ApplyingUpdates | LocalUpdateRemoteUpdate conflict, we basically have the option to 'choose' which database 'wins'.

    I would like to offer the user some kind of merge/edit option, changing the conflicting records to a version which should be committed to both databases.
    Both e.Conflict.LocalChange and e.Conflict.RemoteChange are ReadOnly. I'm able to create copies of both datatables, but how can I persist the 'consensus version' of my records to both local and remote, and continue the sync process?

    This is my code sofar:

    ''' <summary>
    ''' Event handler for 
    ''' AddHandler CType(syncOrchestrator.LocalProvider, SqlSyncProvider).ApplyChangeFailed, AddressOf yncHis_LocalError
    ''' </summary>
    ''' <param name="sender">Typeof SqlSyncProvider</param>
    ''' <param name="e"></param>
    ''' <remarks></remarks>
    Private Sub SyncHis_ServerError(sender As Object, e As DbApplyChangeFailedEventArgs)
        Dim msg As String = "ServerError: " + e.Connection.Database + " ; "
        Dim loc As DataTable = Nothing
        Dim svr As DataTable = Nothing
    
        If e.Conflict IsNot Nothing Then
            'ServerError: AHIS_2 ; ApplyingUpdates | LocalUpdateRemoteUpdate | tblXXX | tblXXX
            msg += e.Conflict.Stage.ToString + "|" + e.Conflict.Type.ToString
            If e.Conflict.LocalChange IsNot Nothing Then
                loc = e.Conflict.LocalChange.Clone
                For Each row As DataRow In e.Conflict.LocalChange.Rows
                    Dim nwRow As DataRow = loc.NewRow
                    nwRow.ItemArray = row.ItemArray
                    loc.Rows.Add(nwRow)
                Next
            End If
            If e.Conflict.RemoteChange IsNot Nothing Then
                svr = e.Conflict.RemoteChange.Clone
                For Each row As DataRow In e.Conflict.RemoteChange.Rows
                    Dim nwRow As DataRow = svr.NewRow
                    nwRow.ItemArray = row.ItemArray
                    svr.Rows.Add(nwRow)
                Next
            End If
    
            ' Present user a conflict resolution screen...
            Using frm As New frmEditConflict(msg, loc, svr)
                Dim rst As DialogResult = frm.ShowDialog()
                If rst = DialogResult.Cancel Then
                    e.Action = ApplyAction.RetryNextSync
                Else
                    ' apply editted rows to server and local...
                    ' How? the following code does not works as intended?
                    If e.Conflict.LocalChange IsNot Nothing Then
                        e.Conflict.LocalChange.Merge(loc, False)
                    End If
                    If e.Conflict.RemoteChange IsNot Nothing Then
                        e.Conflict.RemoteChange.Merge(svr, False)
                    End If
                    e.Action = ApplyAction.RetryWithForceWrite
                End If
            End Using
    
        ElseIf e.Error IsNot Nothing Then
            msg += e.Error.InnerException.Message
        End If
    
        RaiseEvent SyncMessage(Me, New HisSyncEventArgs() With {.Message = msg})
    End Sub

    Or should this be donin an entirely different way? In which case I'm open to suggestions :)
    Wednesday, February 15, 2012 7:01 PM

Answers

  • the rows exposed by the Conflict property are copies of the rows in conflict. the actual rows to be applied are in the Context property, so you should be modifying the row in the Context property.

    see this link for an example: http://msdn.microsoft.com/en-us/library/bb725997.aspx

    there is a sample code in the conflict handling part where it shows a basic merge operation.

    having said that, whatever change you made will only be applied to the destination, not both copies. so in a download scenario, the changed row will be applied in the destination of the download, not the source. you will have to code that separately.

    • Marked as answer by Lextendo Thursday, February 16, 2012 11:07 AM
    Thursday, February 16, 2012 1:45 AM

All replies

  • the rows exposed by the Conflict property are copies of the rows in conflict. the actual rows to be applied are in the Context property, so you should be modifying the row in the Context property.

    see this link for an example: http://msdn.microsoft.com/en-us/library/bb725997.aspx

    there is a sample code in the conflict handling part where it shows a basic merge operation.

    having said that, whatever change you made will only be applied to the destination, not both copies. so in a download scenario, the changed row will be applied in the destination of the download, not the source. you will have to code that separately.

    • Marked as answer by Lextendo Thursday, February 16, 2012 11:07 AM
    Thursday, February 16, 2012 1:45 AM
  • the rows exposed by the Conflict property are copies of the rows in conflict. the actual rows to be applied are in the Context property, so you should be modifying the row in the Context property.

    JuneT, you're awesome!!!

    That did the trick :) Thank you so much.
    I changed the using frm code:

    Using frm As New frmEditConflict(msg, loc, svr, resolve)
        Dim rst As DialogResult = frm.ShowDialog()
        If rst = DialogResult.Cancel Then
            e.Action = ApplyAction.RetryNextSync
        Else
            Dim clientChanges As DataTable = e.Context.DataSet.Tables(resolve.TableName)
            'tblAbc -> AbcID
            Dim IDCol As String = Replace(resolve.TableName, "tbl", String.Empty) + "ID"
    
            Dim colCount As Integer = clientChanges.Columns.Count
            For Each row As DataRow In svr.Rows
                'find context row...
                Dim filter As String = IDCol + "='" + row(0).ToString + "'"
                Dim updateRow As DataRow = clientChanges.Select(filter).FirstOrDefault
                'update context row with resolved values
                If updateRow IsNot Nothing Then
                    For j As Integer = 0 To colCount - 1
                        updateRow(j) = row(j)
                    Next
                End If
            Next
            e.Action = ApplyAction.RetryWithForceWrite
        End If
    End Using

    Thursday, February 16, 2012 11:21 AM