BigBoy1337
BigBoy1337

Reputation: 4973

How to filter ordered items in a Core Data Song/Playlist type of relationship?

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

enter image description here

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

Answers (1)

BigBoy1337
BigBoy1337

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

Related Questions