Primary photo (child record created with parent) silently dropped on receiving device due to FK ordering #437
Replies: 1 comment
-
Hi @camdenwebster, I am not able to reproduce this. The reminders demo app has assets, and to test I updated the entry point of the app to immediately create a list + image: Task {
@Dependency(\.defaultDatabase) var database
try await database.write { db in
let id = try RemindersList.insert {
RemindersList.Draft(title: "TEST")
}
.returning(\.id)
.fetchOne(db)!
try RemindersListAsset.insert {
RemindersListAsset.Draft(remindersListID: id, coverImage: Data([0xde,0xad,0xbe,0xef]))
}
.execute(db)
}
}That synchronized to iCloud just fine, and when I delete and reinstall the app from scratch that list + asset came through. I also tested this by creating a reminders list, asset, and a bunch of reminders all at the same time, and that too synchronized just fine.
That is not how the
This would not fix anything because by the very nature of the remote synchronizing it is possible to receive child records long before parent records are received, and so will not be apart of the same transaction. Since I'm not sure this is an issue with the library I am going to convert it to a discussion. Please provide more information on how to reproduce and we can take another look at it. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
Summary
When a parent record and an associated child record (with a
DataBLOB column) are created in the samedatabase.writetransaction on Device A, the child record is silently dropped on Device B during CloudKit sync. Child records created in later, separate transactions sync correctly.Environment
Reproduction
Schema
SyncEngine registration (both tables present, FK enforcement enabled):
Write path that triggers the bug
Write path that works correctly
Observed behaviour
Root cause hypothesis
"inventoryItemPhotos" < "inventoryItems"alphabetically ('P'<'s'). If the SyncEngine inserts incoming CKRecords sorted byrecordTypename, the photo row is attempted before its parent item row exists in the local SQLite database. WithforeignKeysEnabled = truethis causes a FK constraint violation; the row is silently dropped and the item row succeeds.This theory is consistent with:
The same pattern likely affects any table pair where the child table name sorts alphabetically before the parent:
homePhotos<homes('P'<'s')inventoryLocationPhotos<inventoryLocationsExpected behaviour
The SyncEngine should ensure parent records are written to the local database before child records that reference them, regardless of how incoming CKRecords are ordered by CloudKit. This could be achieved by topologically sorting records by their FK dependencies before inserting, or by temporarily deferring FK checks during batch inserts.
Workaround
A per-constraint
DEFERRABLE INITIALLY DEFERREDFK causes SQLite to defer the check until transaction commit, by which point all records in the batch should be present:This resolves the symptom. If the ordering behaviour is intentional or the root cause is elsewhere, happy to provide more diagnostic information.
Beta Was this translation helpful? Give feedback.
All reactions