locked
Custom LastSentAnchor RRS feed

  • Question

  • We do need to override Sent Anchor in Sql Ce database, because we have to get the date and time when the last change was sent from SqlCe database to Sql Server. We tried to override few functions to create the  custom anchor, but the synchronisation fails every time. 

    What we tried:

    Using the class with two functions to expand and collapse anchor:

    Public Class customAnchor
    
        Public timeStamp As Byte()'the original anchor value
        Public lastSyncTime As Nullable(Of DateTime)'the dateTime extention

    Public Shared Sub ShrinkAnchor(ByRef simpleAnchor As Microsoft.Synchronization.Data.SyncAnchor) If simpleAnchor IsNot Nothing AndAlso simpleAnchor.Anchor IsNot Nothing Then Dim formater As BinaryFormatter = Nothing Dim mstream1 As IO.MemoryStream = Nothing Try formater = New BinaryFormatter
    mstream1 = New IO.MemoryStream(simpleAnchor.Anchor) Dim obj As Object = formater.Deserialize(mstream1) If TypeOf obj Is customAnchor Then
    Dim custAnchor As customAnchor = CType(obj, customAnchor) If custAnchor IsNot Nothing Then simpleAnchor.Anchor = custAnchor.timeStamp End If End If Catch ex As Exception Finally formater = Nothing If mstream1 IsNot Nothing Then mstream1.Close() mstream1.Dispose() mstream1 = Nothing End If End Try End If End Sub

    Public
    Shared Sub ExpandAnchor(ByRef simpleAnchor As Microsoft.Synchronization.Data.SyncAnchor) Dim formater As BinaryFormatter = Nothing Dim mstream1 As IO.MemoryStream = Nothing Try
    If simpleAnchor IsNot Nothing AndAlso simpleAnchor.Anchor IsNot Nothing Then formater = New BinaryFormatter Dim custAnchor As New customAnchor custAnchor.timeStamp = simpleAnchor.Anchor custAnchor.lastSyncTime = Date.Now mstream1 = New IO.MemoryStream formater.Serialize(mstream1, custAnchor) simpleAnchor.Anchor = mstream1.ToArray End If Catch ex As Exception Finally formater = Nothing If mstream1 IsNot Nothing Then mstream1.Close() mstream1.Dispose() mstream1 = Nothing End If End Try End Sub End Class

    1.Overriding SetTableSentAnchor  and GetTableSentAnchor 
    2.Overriding ApplyChanges(DbServerSyncProvider) and GetChanges(SqlCeClientSyncProvider). We also tried to interchange the overriding between DbServerSyncProvider and SqlCeClientSyncProvider , but it also doesn't work.

     

    Public Overrides Sub SetTableSentAnchor(ByVal tableName As String, ByVal anchor As Microsoft.Synchronization.Data.SyncAnchor)
    
     	customAnchor.ExpandAnchor(anchor)
    	MyBase.SetTableSentAnchor(tableName, anchor)
    End Sub
    Public Overrides Function GetTableSentAnchor(ByVal tableName As String) As Microsoft.Synchronization.Data.SyncAnchor Dim simpleAnchor As Microsoft.Synchronization.Data.SyncAnchor = MyBase.GetTableSentAnchor(tableName) customAnchor.ShrinkAnchor(simpleAnchor) Return simpleAnchor
    End Function

     

    Public Overrides Function GetChanges(ByVal groupMetadata As Microsoft.Synchronization.Data.SyncGroupMetadata, ByVal syncSession As Microsoft.Synchronization.Data.SyncSession) As Microsoft.Synchronization.Data.SyncContext
    
    	For Each _table As Microsoft.Synchronization.Data.SyncTableMetadata In groupMetadata.TablesMetadata
    		customAnchor.ShrinkAnchor(_table.LastSentAnchor)
    	Next
    	Dim cxt As Microsoft.Synchronization.Data.SyncContext = Nothing
    	Try
     		cxt = MyBase.GetChanges(groupMetadata, syncSession)
    		customAnchor.ExpandAnchor(cxt.NewAnchor)
    	Catch ex As Exception
    		Throw ex
    	End Try
     		Return cxt
    End Function
    
    Public Overrides Function ApplyChanges(ByVal groupMetadata As Microsoft.Synchronization.Data.SyncGroupMetadata, ByVal dataSet As System.Data.DataSet, ByVal syncSession As Microsoft.Synchronization.Data.SyncSession) As Microsoft.Synchronization.Data.SyncContext
    	For Each _table As Microsoft.Synchronization.Data.SyncTableMetadata In groupMetadata.TablesMetadata
    		customAnchor.ShrinkAnchor(_table.LastSentAnchor)
    	Next
    	Dim cxt As Microsoft.Synchronization.Data.SyncContext = Nothing
    	Try
    		cxt = MyBase.ApplyChanges(groupMetadata, dataSet, syncSession)
    	Catch ex As Exception
    		Throw ex
    	End Try
    		Return cxt
    End Function

     

      • The StackTrace of the exception we get:
    à System.Convert.ToInt64(UInt64 value) à System.UInt64.System.IConvertible.ToInt64(IFormatProvider provider) à System.Data.SqlServerCe.Accessor.set_Value(Object value) à System.Data.SqlServerCe.SqlCeCommand.FillParameterDataBindings() à System.Data.SqlServerCe.SqlCeCommand.ExecuteCommand(CommandBehavior behavior, String method, ResultSetOptions options) à System.Data.SqlServerCe.SqlCeCommand.ExecuteNonQuery() à Microsoft.Synchronization.Data.SqlServerCe.SqlCeClientSyncProvider.SystemCommandExecuteNonQuery(SqlCeCommand cmd) à Microsoft.Synchronization.Data.SqlServerCe.SqlCeClientSyncProvider.ApplyUpdate(SyncTableMetadata tableMetadata, UInt64 lastSentAnchorValue, DataRow dataRow, ApplyAction action, SqlCeException& error) à Microsoft.Synchronization.Data.SqlServerCe.SqlCeClientSyncProvider.ApplyUpserts(SyncTableMetadata tableMetadata, SyncTableProgress tableProgress, SyncGroupMetadata groupMetadata, DataTable dataTable, DataRowState applicableState, UInt64 lastSentAnchorValue, SyncSession syncSession) à Microsoft.Synchronization.Data.SqlServerCe.SqlCeClientSyncProvider.ApplyChanges(SyncGroupMetadata groupMetadata, DataSet dataSet, SyncSession syncSession) à Microsoft.Synchronization.SyncAgent.DownloadChanges(SyncGroupMetadata groupMetadata) à Microsoft.Synchronization.SyncAgent.DataSynchronize() à Microsoft.Synchronization.SyncAgent.Synchronize() à Atlibitum.ADN.Sync.Core.Agent.GetData()

    Any ideas?
    Thanks in advance for the response.

    • Edited by innai Tuesday, December 8, 2009 8:29 AM
    • Moved by Max Wang_1983 Tuesday, April 19, 2011 10:41 PM Forum consolidation (From:SyncFx - Microsoft Sync Framework Database Providers [ReadOnly])
    Monday, December 7, 2009 1:30 PM

Answers

  • The anchor command SyncNewReceivedAnchor type doens't match the ShrinkAnchor settings (simpleAnchor.Anchor = custAnchor.timeStamp).
    It is a mismatch of DateTime type and TimeStamp type.

    You can change the command to use Binary(8) type and select it as @@dbts.
    Wednesday, December 9, 2009 11:02 PM
    Answerer
  • Please consider an alternative approach. A custom anchor may not need to achieve your objective.

    I reckon you want to guarantee that client changes will be uploaded again in case server database is restored a backup and lose some of the previous uploaded changes. In this case, my solution is:
    • store the new anchor at the server side each time client upload changes 
    • before uploading, get the anchor from server and set the anchor at client db
    If you only care the date time, why don't you store them in your own table?

    Sunday, December 13, 2009 12:36 AM

All replies

  • What's the exception message?
    From the code above, it doesn't seem to me the timestamp in custom anchor is updated with the datetime. Please check whether the value is intended.

    Monday, December 7, 2009 7:34 PM
    Answerer
  • Hi, thanks for the reply,
    the exception message is in french, it says that the value for int64 is too big or too small.
    Our customAnchor class has two  variables: "timeStamp" of byte array type and "lastSyncTime" of dateTime type. The "timeStamp" variable holds the original anchor byte array and the lastSyncTime is affected of the Date.Now value in the expandAnchor() function.
    I checked in the __sysSyncArticles table, after then expandAnchor() function, the value of sentAnchor is longer then original anchor. So, i believe it contains the original anchor value and the dateTime value serialized together. After reading the lastSentAnchor, the dateTime value seems to be correct, it also works without exceptions if there is no data to transport. But, during the import of data the exception occurs.
    ???
    Tuesday, December 8, 2009 9:15 AM

  • Is the timestamp is really intended for use as anchor? What's the lastSyncTime for?

    can you please provide the serverProvider.SelectNewAnchorCommand implementation including command text and parameters(including types) ?

    Tuesday, December 8, 2009 10:21 PM
    Answerer


  • My anchor is of type dateTime.

    Me.SelectNewAnchorCommand = New System.Data.SqlClient.SqlCommand
    Dim newAnchorParam As System.Data.SqlClient.SqlParameter = Nothing
    
    Me.SelectNewAnchorCommand.CommandText = "Select @" & SyncSession.SyncNewReceivedAnchor & " = GETDATE()"
    newAnchorParam = New System.Data.SqlClient.SqlParameter("@" & SyncSession.SyncNewReceivedAnchor, System.Data.SqlDbType.DateTime)
    
    newAnchorParam.Direction = System.Data.ParameterDirection.Output
    Me.SelectNewAnchorCommand.Parameters.Add(newAnchorParam)

    I noticed that i can deserialize the received anchor and get directely the dateTime value, but the deserialization of sent anchor throws the exception, so i gess it is not of datetime type. So i tried to extand the anchor myself...without success.
     
    Custom anchor class:
    -timestamps is intended for the original byte array of sentAnchor. The lastSyncTime is the extention to remember the dateTime.

    Wednesday, December 9, 2009 8:27 AM
  • The anchor command SyncNewReceivedAnchor type doens't match the ShrinkAnchor settings (simpleAnchor.Anchor = custAnchor.timeStamp).
    It is a mismatch of DateTime type and TimeStamp type.

    You can change the command to use Binary(8) type and select it as @@dbts.
    Wednesday, December 9, 2009 11:02 PM
    Answerer
  • Please consider an alternative approach. A custom anchor may not need to achieve your objective.

    I reckon you want to guarantee that client changes will be uploaded again in case server database is restored a backup and lose some of the previous uploaded changes. In this case, my solution is:
    • store the new anchor at the server side each time client upload changes 
    • before uploading, get the anchor from server and set the anchor at client db
    If you only care the date time, why don't you store them in your own table?

    Sunday, December 13, 2009 12:36 AM
  • Ok, we found the solution the other way.
    We needed to overload the sentAnchor, so there is nothing i can do about the syncNewReceivedAnchor. Apparently, it is not possible to overload the sentAnchor, but only the receivedAnchor. So it is not possible to store the time when changes were sent to server using sentAnchor . So i store this value in my own table, overloading SetTableSentAnchor() sub.

    Thanks for your reply

    Tuesday, December 29, 2009 8:41 AM