I have to periodically push sync (Make destination the same as source) between 2 databases (Eventually FB to SQLite, but for now sqlite to sqlite). I have sync'd datasets a number of times over my programming career and have some specific to the use case and some more generic solutions.
As the datasets are relatively small I decided to try using TFDBatchmove in the hope it might not be super efficient, but would be a case of hooking up some components and pressing the Go button :-). A day later and I still haven't got it working.
I intended building from a very trivial example. I also had a look at the samples for D12.1, which in a classic sample fashion wasn't super clear to read the code.
So Q1) is it suitable to us use the batchmove components in this way?
Current test: 2 identical tables in sqlite, run it once, it fills the table (that actually works)
Modify the destination table (e.g. blank a few field values)
Rerun and initially I get an exception "Not Implemented"
By trial and error I add in an event handler for OnFindDestRecord - which I thought I wouldn't need as I am using TFDTable, the sqlite table has a primary key and the field structures are identical.
Now I have hand coded the locate from source to destination it gives me:
Project FDBatchMoveScratch.exe raised exception class EFDDBEngineException with message '[FireDAC][Phys][SQLite]-312. Exact update affected [0] rows, while [1] was requested'.
Project FDBatchMoveScratch.exe raised exception class EFDException with message '[FireDAC][DApt]-400. Update command updated [0] instead of [1] record. Possible reasons: update table does not have PK or row identifier, record has been changed/deleted by another user'.
Adding in event handlers for all of the batch move events, to try and work out what is going on - it is trying to update the 1st row, eventhough the row is identical.
So I am clearly missing something (or a lot of things).
For info - I have 2 FDConnections, an FDBatchMove, in fact to avoid ambiguity, I've pasted the objects below .
Q2) Can anyone point me to a decent walk through of setting up one way sync and resync.
I could have hand coded a compare, update, insert, delete routine by hand in this time :-(.
As always, thank you for your time with this.
object FDBatchMove1: TFDBatchMove
Reader = FDBatchMoveDataSetReader1
Writer = FDBatchMoveDataSetWriter1
Mode = dmAppendUpdate
Options = [poIdentityInsert, poSkipUnmatchedDestFields, poUseTransactions]
Mappings = <>
LogFileAction = laAppend
LogFileName = 'Data.log'
OnProgress = FDBatchMove1Progress
OnFindDestRecord = FDBatchMove1FindDestRecord
OnWriteValue = FDBatchMove1WriteValue
OnWriteRecord = FDBatchMove1WriteRecord
Left = 384
Top = 216
end
object FDBatchMoveDataSetReader1: TFDBatchMoveDataSetReader
DataSet = tblsrcWebUsers
Left = 520
Top = 120
end
object FDBatchMoveDataSetWriter1: TFDBatchMoveDataSetWriter
Direct = True
DataSet = tbldestWebUsers
Left = 512
Top = 296
end
object tbldestWebUsers: TFDTable
IndexFieldNames = 'ID'
Connection = FDConnectionSQLiteDest
ResourceOptions.AssignedValues = [rvEscapeExpand]
TableName = 'WEB_USERS'
Left = 376
Top = 288
object tbldestWebUsersID: TIntegerField
FieldName = 'ID'
Origin = 'ID'
ProviderFlags = [pfInUpdate, pfInWhere, pfInKey]
Required = True
end
object tbldestWebUsersUSERNAME: TStringField
FieldName = 'USERNAME'
Origin = 'USERNAME'
Required = True
Size = 50
end
object tbldestWebUsersROLE: TStringField
FieldName = 'ROLE'
Origin = 'ROLE'
Size = 50
end
object tbldestWebUsersIS_ACTIVE: TIntegerField
FieldName = 'IS_ACTIVE'
Origin = 'IS_ACTIVE'
end
object tbldestWebUsersCOMPANY_NAME: TStringField
FieldName = 'COMPANY_NAME'
Origin = 'COMPANY_NAME'
Size = 50
end
end