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