I'm running into an odd case where a model's reverse relationship is sometimes not set despite the forward relationship being there.
If the app is closed and reopened however, the reverse relationship for previously added data works.
For example, given three models Shelf, Item and ItemDetails:
@Model final class Shelf {
@Relationship(deleteRule: .cascade, inverse: \Item.primaryShelf)
var items: [Item] = []
init() {}
}
@Model final class Item {
var primaryShelf: Shelf?
var timestamp: Date
@Relationship(deleteRule: .cascade, inverse: \ItemDetail.item)
public var detail: ItemDetail?
init(primaryShelf: Shelf) {
self.primaryShelf = primaryShelf
self.timestamp = .now
}
}
@Model final class ItemDetail {
var item: Item?
init(item: Item) { self.item = item }
}
Now I want to simply create a shelf, some items and some itemdetails.
@Test func testRelationshipsThroughInit() async throws {
let schema = Schema([Shelf.self, Item.self, ItemDetail.self])
let config = ModelConfiguration(schema: schema, isStoredInMemoryOnly: true)
let container = try ModelContainer(for: schema, configurations: [config])
let modelContext = ModelContext(container)
let shelf = Shelf()
modelContext.insert(shelf)
for _ in 0..<10 {
let item = Item(primaryShelf: shelf)
modelContext.insert(item)
let itemDetail = ItemDetail(item: item)
modelContext.insert(itemDetail)
}
try modelContext.save()
let fetchDescriptor = FetchDescriptor<Shelf>()
let shelves = try modelContext.fetch(fetchDescriptor)
// fails with a random number between 0 and 9 typically
#expect(shelves.first?.items.count == 10)
}
There seem to be two ways that this problem goes away. The first is changing the order of properties set in ItemDetail.init() so that the relationship is set after everything else:
@Model final class Item {
// ...
init(primaryShelf: Shelf) {
self.timestamp = .now
self.primaryShelf = primaryShelf
}
With this, everything seems to work fine. The other way seems to be manually setting the reverse relationship. So the loop above gets changed to:
for _ in 0..<10 {
let item = Item(primaryShelf: shelf)
modelContext.insert(item)
let itemDetail = ItemDetail(item: item)
modelContext.insert(itemDetail)
// add reverse relationship even though forward was set
shelf.items.append(item)
}
My question is, is this the expected behavior and If so, is there any place this is documented?