Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

HowTo create predicate for object count several relationships deep? Core Data iOS Swift

I have a rather vexing issue that I have not yet been able to find an answer to, and was hoping you could help! My situation is this: I have the following object model in Core Data

Scenes <-->>Characters<-->>Lines

The entities have the relationships: Scenes->toCharacters->Characters->toLines->Lines

What I am trying to accomplish is to fetch all Scenes where there exist characters who actually have lines.

Every article I've read talks about simply "Walking The Graph", and this DOES work, but not all the way down to the Lines entity.

For example, this predicate works just fine, goes one level deep and retrieves all scenes which contain characters:

    let scene_ent:NSEntityDescription = NSEntityDescription.entityForName("Scenes", inManagedObjectContext: context)

    scenerequest.entity = scene_ent

    let predicate:NSPredicate = NSPredicate(format: "toCharacters.@count > 0")        
    scenerequest.predicate = predicate

When I try to modify the predicate to instead retrieve all scenes which contain characters who have lines:

    let predicate:NSPredicate = NSPredicate(format: "toCharacters.Characters.toLines.@count > 0")   

I get the error 'Unsupported function expression count:(toCharacters.Characters.toLines)'

Is there something really simple that I'm missing here?

thanks!

like image 814
CodeNoob Avatar asked Sep 11 '14 18:09

CodeNoob


People also ask

What is core data in Swift?

Core Data is a powerful mobile database allowing developers to create high performance, data-driven iOS and macOS applications. This post presents examples of creating, updating, and deleting Core Data objects in Swift: a. New Data Model Entity Using Xcode b. Xcode NSManagedObject Sync a. New NSManagedObject Example b.

How do I create one-to-many relationships in core data?

Let's finish with a look at one-to-many relationships. Open Core_Data.xcdatamodeld, select the Person entity, and create a relationship named children. Set the destination to Person, set the type to To Many, and leave the inverse relationship empty for now.

How do I work with a one-to-one relationship between two objects?

Working with a one-to-one relationship is identical to working with attributes. The only difference is that the value you get back from valueForKey (_:) and the value you pass to setValue (_:forKey:) is an NSManagedObject instance. Let's update the data model to illustrate this.

How does core data handle inverse relationships?

Core Data creates this relationship for us. If a relationship has an inverse relationship, then Core Data takes care of this automatically. You can verify this by asking newAddress for its persons. Updating a relationship isn't difficult either.


1 Answers

The key paths in the predicate use only the relationships, not the entity names, so

NSPredicate(format: "toCharacters.Characters.toLines.@count > 0")

should be

NSPredicate(format: "toCharacters.toLines.@count > 0")

but that will probably not work either. This might work (cannot test this at the moment):

NSPredicate(format: "ANY toCharacters.toLines.@count > 0")

and I am quite sure that this will work:

NSPredicate(format: "SUBQUERY(toCharacters, $c, $c.toLines.@count > 0).@count > 0")

Update: The correct solution is

NSPredicate(format: "SUBQUERY(toCharacters, $c, ANY $c.toLines != NULL).@count > 0")
like image 69
Martin R Avatar answered Oct 19 '22 23:10

Martin R