18
votes

I'm scratching my head on this one. I have a work around, but I don't understand it so that doesn't count. What I want to do is for the entity (in this case a "Photo" lets say), I want to find all the Photos reviewed by anyone OTHER than the specified user. The relationship here is Photo->Review->User, where a photo can have multiple reviews, and each review is owned by exactly one user. The first two examples were my logical first attempts, but does not work. I found some similar code that shows the subquery which works, but can anyone explain why the first two examples don't work?

// this does not work
[NSPredicate predicateWithFormat:@"NOT (ANY reviews.user = %@)", self.user]

// this does not work
[NSPredicate predicateWithFormat:@"NONE reviews.user = %@", self.user]

// this works
[NSPredicate predicateWithFormat:@"SUBQUERY(reviews, $x, $x.user == %@).@count == 0", self.user];
4
You are correct, this won't work for a to-many, how is your entity model constructed such that reviews.user is a to-many relationship? - ImHuntingWabbits
It should work (first and second examples). ImHuntingWabbits is probably on the right track, your model might be screwed up. Can you post a sample project or do you need one as an example? - Allen Ding
I have the same issue, cannot negate relationships with NOT or NONE, only using a subquery. - lkraider
I have this exact same problem - any fix?? - mootymoots
@Duane Fields, how did you end up solving this? I have the exact same problem. None of the suggestions here work except for the subquery. How did you solve this? Or did you stick with the subquery? - thephatp

4 Answers

3
votes

try this

NSPredicate *predicate = [NSCompoundPredicate notPredicateWithSubpredicate:[NSPredicate predicateWithFormat:@"ANY reviews.user = %@", self.user]];
0
votes
[NSPredicate predicateWithFormat:@"NOT reviews.user = %@", self.user]
-1
votes

The problem is that you want to compare relationships in your predicate rather than attributes. Your User should have a unique attribute, such as name. I suggest that you use it in your predicate in the following way:

NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Photo"];
NSPredicate * p = [NSPredicate predicateWithFormat:@"ANY comments.user.name != %@", @"John Smith"];
// NSPredicate * p = [NSPredicate predicateWithFormat:@"NONE comments.user.name == %@", @"John Smith"];
request.predicate = p;
-1
votes

I find it is better to perform Core Data relationship comparisons by comparing unique identifiers of the entity in question rather than the entity itself. For example, in my app I have an entity called User, which has an attribute objectId. (Note: this is not to be confused with the internal objectID of the Core Data object. The objectId is simply a unique primary key from my external DB. Then, your predicate would look like this:

NSPredicate *predicate = [NSPredicate predicateWithFormat@"ANY reviews.user.objectId != %@", self.user.objectId];