I also filed one for the same issue: FB16858906
In addition, prefetching related models will also prefetch pks for any one-to-many models in the related model which is unexpected and not desired.
Given:
@Model final class OrderItem {
var quantity: Int
var sku: Int
var order: Order? = nil
init(quantity: Int, sku: Int) {
self.quantity = quantity
self.sku = sku
}
}
@Model final class Order {
var orderID: Int
var timestamp: Date = Date()
var account: Account?
@Relationship(deleteRule: .cascade, inverse: \OrderItem.order)
var orderItems: [OrderItem]? = []
init(orderID: Int) { self.orderID = orderID }
}
@Model final class Account {
var accountID: Int
@Relationship(deleteRule: .cascade, inverse: \Order.account)
var orders: [Order]? = []
init(accountID: Int) { self.accountID = accountID }
}
With some sample data:
let account = Account(accountID: 1)
modelContext.insert(account)
let order = Order(orderID: 100)
modelContext.insert(order)
order.account = account
let orderItem = OrderItem(quantity: 1, sku: 999)
modelContext.insert(orderItem)
orderItem.order = order
Trying to fetch Accounts and pre-fetch related Orders results in 5 queries rather than 2:
var fd = FetchDescriptor<Account>()
fd.relationshipKeyPathsForPrefetching = [\.orders]
let accounts = modelContext.fetch(fd)
// CoreData: sql: SELECT 0, t0.Z_PK, t0.Z_OPT, t0.ZACCOUNTID FROM ZACCOUNT t0
// CoreData: sql: SELECT 0, t0.Z_PK, t0.Z_OPT, t0.ZORDERID, t0.ZTIMESTAMP, t0.ZACCOUNT FROM ZORDER t0 WHERE t0.ZACCOUNT IN (SELECT * FROM _Z_intarray0) ORDER BY t0.ZACCOUNT
// CoreData: sql: SELECT 0, t0.Z_PK FROM ZORDERITEM t0 WHERE t0.ZORDER = ?
for account in accounts {
if let orders = account.orders {
for order in orders {
let orderID = order.orderID
// CoreData: sql: SELECT 0, t0.Z_PK, t0.Z_OPT, t0.ZORDERID, t0.ZTIMESTAMP, t0.ZACCOUNT FROM ZORDER t0 WHERE t0.Z_PK IN (?)
// CoreData: sql: SELECT 0, t0.Z_PK FROM ZORDERITEM t0 WHERE t0.ZORDER = ?
}
}
}