user2924482
user2924482

Reputation: 9140

core data in one to many to many relation query

I have a core data object like this:

enter image description here

I build a predicate to get scheduletimes and per selection times I need to get the movies and theaters

With the value of the schedule I tried to get theater

Here is my code:

 NSString *nameOfMovie = [[scheduleResults movie] valueForKey:@"nameOfMovie"];

NSPredicate *theaterPredicate  = [NSPredicate predicateWithFormat:@"SUBQUERY (showTimes, $x, $x.nameOfMovie == %@ AND $x.showTimes.showTimes == %@).@count > 0", nameOfMovie, showTimes];

But I'm getting this error with my predicate:

to-many key not allowed here

any of you knows what I'm doing wrong with my predicate?

Upvotes: 0

Views: 99

Answers (1)

Sandeep
Sandeep

Reputation: 21154

I found the question quite interesting and so create a simple playground with swift to test the subquery for your case. I think you are missing some relations in your data model, if you really care about it, and you should name the entities in singular like Movie, Schedule, Theater etc which makes more sense, since entities are always singular and associations can be singular or plural depending on one-to-many or one-to-one relation.

Here is what I have come up with the data model,

// a Movie can have multiple schedule and a schedule can have multiple movies at the same time
Schedule << -------  >> Movie

// a Movie can be running in multiple theater and a theater can have multiple movies
Movie << ------>> Theater

So, based on the above relation, I created a playground file to create some fixture data and play around,

class Schedule: NSObject {
    var showTime: NSDate!
    var movies: [Movie]!
}

class Theater: NSObject {
    var name: String!
    var movies: [Movie]!
}

class Movie: NSObject {
    var nameOfMovie: String!
    var theaters: [Theater]!
    var showTimes: [Schedule]!
}

let hitech = Theater()
hitech.name = "Hitech Cinema"

let kino = Theater()
kino.name = "Kino"

let warner = Theater()
warner.name = "Warners"


let interstellar = Movie()
interstellar.nameOfMovie = "Interstellar"

let gravity = Movie()
gravity.nameOfMovie = "Gravity"

let wrathOfSpace = Movie()
wrathOfSpace.nameOfMovie = "Wrath of Space"

let today = NSDate()
let yesterday = today.dateByAddingTimeInterval(-60 * 60 * 24)
let tomorrow = today.dateByAddingTimeInterval(60 * 60 * 24)


let todaySchedule = Schedule()
todaySchedule.showTime = today

let yesterdaySchedule = Schedule()
yesterdaySchedule.showTime = yesterday

let tomorrowSchedule = Schedule()
tomorrowSchedule.showTime = tomorrow


todaySchedule.movies = [interstellar, gravity]
tomorrowSchedule.movies = [interstellar, wrathOfSpace]
yesterdaySchedule.movies = [wrathOfSpace, gravity]

interstellar.showTimes = [todaySchedule, tomorrowSchedule]
gravity.showTimes = [todaySchedule, yesterdaySchedule]
wrathOfSpace.showTimes = [tomorrowSchedule, yesterdaySchedule]

interstellar.theaters = [kino, hitech]
gravity.theaters = [kino, warner]
wrathOfSpace.theaters = [warner, hitech]

kino.movies = [interstellar, gravity]
hitech.movies = [interstellar, wrathOfSpace]
warner.movies = [wrathOfSpace, gravity]


let theaters:NSArray = [hitech, warner, kino]


var nameOfMovie = "Gravity"
var date = yesterday

var predicate = NSPredicate(format: "SUBQUERY(movies, $a, $a.nameOfMovie = %@ and SUBQUERY($a.showTimes, $b, $b.showTime = %@).@count > 0).@count > 0", nameOfMovie, date)

let threatersYesterdayGravity = theaters.filteredArrayUsingPredicate(predicate)


nameOfMovie = "Interstellar"
date = tomorrow

predicate = NSPredicate(format: "SUBQUERY(movies, $a, $a.nameOfMovie = %@ and SUBQUERY($a.showTimes, $b, $b.showTime = %@).@count > 0).@count > 0", nameOfMovie, date)

let threatersTomorrowInterstellar = theaters.filteredArrayUsingPredicate(predicate)

And the result are as I would expect. You can also play with the above relation and subquery fit it to your need.

Upvotes: 1

Related Questions