Reputation: 4973
I have two entities - Skill and SkillGroup order in a many-to-many relationship. I am trying to save the display order of the skill's in the skill group and allow the user to re-order them.
I've realized that this is the same type of relationship you would have in a Song/Playlist relationship. Furthermore, the advice online for those relationships indicates that you can model this with an inbetween "ordering" entity which actually keeps track of the index for the song in the playlist. So I've decided to use this strategy for my Skill and SkillGroup and SkillGroupOrder entities
Now Im trying to display all the skills for a particular SkillGroup and trying to format the NSPredicate. I have
fetchRequest.predicate = NSPredicate(format: "ANY skillGroupOrders.group = %@", skillGroup)
However, with that predicate, I get keypath skillGroupOrders.group not found in entity <NSSQLEntity Skill id=5> with userInfo of (null)
I think maybe its having trouble because its trying to do this "chained" filtering.
When I remove the predicate, I can successfully query the skills, and in the debugger, I can do
po skills.first?.skillGroupOrders;
CoreData: sql: SELECT 0, t0.Z_PK FROM ZSKILLGROUPORDER t0 WHERE t0.ZSKILL = ?
CoreData: annotation: sql connection fetch time: 0.0001s
CoreData: annotation: total fetch execution time: 0.0002s for 2 rows.
CoreData: annotation: to-many relationship fault "skillGroupOrders" for objectID 0xdd03d34ec2525fde <x-coredata://0D3C2790-6F48-45AF-8472-3CEE200428FB/Skill/p1> fulfilled from database. Got 2 rows
▿ Optional<NSSet>
▿ some : 2 elements
- 0 : <SkillGroupOrder: 0x600002bca670> (entity: SkillGroupOrder; id: 0xdd03d34ec25e5fd4 <x-coredata://0D3C2790-6F48-45AF-8472-3CEE200428FB/SkillGroupOrder/p2>; data: <fault>)
- 1 : <SkillGroupOrder: 0x600002bca800> (entity: SkillGroupOrder; id: 0xdd03d34ec25a5fd4 <x-coredata://0D3C2790-6F48-45AF-8472-3CEE200428FB/SkillGroupOrder/p3>; data: <fault>)
But Im not sure how to filter these on having that skillsGroupOrders' group be the skillGroup...
Upvotes: 1
Views: 80
Reputation: 4973
My code was actually fine. @Larme was right that I had a typo basically in calling it group rather than skillGroup.
However, I realized with the help of some other answers that you can do this a lot more effectively by fetching the intermediate item SkillGroupOrder instead. That way you can filter on
fetchRequest.predicate = NSPredicate(format: "skillGroup = %@", skillGroup)
and then sort on
fetchRequest.sortDescriptors = [NSSortDescriptor(key: "displayOrder", ascending: true)]
Then, when you re-order the items in the table, you have to manually update the displayOrder with your own algorithm. Here's mine:
func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }
let managedContext = appDelegate.persistentContainer.viewContext
//For me I had an extra row to add more skills. If you don't have this, that wouldn't be necessary
let source_index = sourceIndexPath.row - 1
let destination_index = destinationIndexPath.row - 1
let sourceItem = skillGroupItems[source_index]
sourceItem.displayIndex = Int16(destination_index)
if destination_index < source_index {
for index in destination_index..<source_index {
let item = skillGroupItems[index]
item.displayOrder = Int16(item.displayOrder) + 1
}
} else if destination_index > source_index {
for index in source_index + 1..<destination_index + 1 {
let item = skillGroupItems[index]
item.displayOrder = Int16(item.displayOrder) - 1
}
}
do { try
managedContext.save()
} catch let error as NSError {
print("Could not update orderings of skillGroupItems. \(error), \(error.userInfo)")
}
}
Then when you re-run the fetch request and reload the table, the sort descriptor works properly on those manually updated rows.
If anyone needs additional detail, let me know.
Upvotes: 0