Core Data, NSPredicate and to-many key

33,774

Solution 1

with the help of you all, I finally managed to determine the correct predicate for my scenario. It looks like that an NSDate object is handled as a double, however, the double is never something like 3.7, it is always like 3.0 Therefore, the following predicate correctly works in my tests:

NSPredicate *occurrenceIsNotExcludedPredicate = [NSPredicate predicateWithFormat: @"(excludedOccurrences.@count == 0 || (excludedOccurrences.@count > 0 && NONE excludedOccurrences.start == %@))",thisDate];

where thisDate is a NSDate object containing only the day, month and year components (as in the case of the start property of the ExcludedOccurrence entity.

Testing for an empty relationship is basically done using the @count aggregate operator, as suggested by some folks at Apple.

Again, thankyou very much for your help. I still observe that the documentation is flawed in several parts (especially where it says that ALL works fine while, instead, it does not work at all).

Solution 2

To test for an empty relationship you should compare the count of the to-many key to zero.

[NSPredicate predicateWithFormat:@"excludedOccurrences.@count == 0"];

As for your subpredicates, be aware that you can only have one of either the ALL or ANY modifiers in your final predicate, although you can use that modifier multiple times throughout the predicate.

Not OK: ANY foo.bar = 1 AND ALL foo.baz = 2
OK: ANY foo.bar = 1 AND !(ANY foo.baz != 2)

Solution 3

So, to test for a non-empty relationship, this actually works:

[NSPredicate predicateWithFormat:@"relationship.@count != 0"]

The solution given by Ashley Clark crashes for me giving "to-many key not allowed here"

Solution 4

And in swift 2, something like:

request.predicate = NSPredicate(format: " relationship.@count != 0")
Share:
33,774
Massimo Cafaro
Author by

Massimo Cafaro

Associate Professor at the University of Salento, Italy. A computer scientist, whose research is centered around Data Mining, Machine Learning, High Performance, Distributed and Grid/Cloud Computing. Especially interested to the design, analysis and implementation of parallel and distributed algorithms. Developing for the unix environment since 1987, for Mac OS since 1988, and for iOS since 2008.

Updated on July 09, 2022

Comments

  • Massimo Cafaro
    Massimo Cafaro almost 2 years

    I have a Core Data model in which a Task entity includes an optional to-many relationship excludedOccurrences. One of the properties of excludedOccurrences is start, which is an NSDate object. The ExcludedOccurrence entity has an inverse mandatory to-one relationship to the Task entity.

    In order to fetch tasks for a specified day, I need to make sure that the specified day does not appear as the start property of any ExcludedOccurrence entity. One of the sub-predicates I am trying to use is therefore

    NSPredicate *occurrenceIsNotExcludedPredicate = [NSPredicate predicateWithFormat: @"(ALL excludedOccurrences.start != %@))", today];
    

    where today is a NSDate object for today including only the day, month and year components. All of the excluded occurrences start properties also include just the day, month and year components.

    While this should fine, at least reading the documentation for Core Data and NSPredicate, I get the following error message:

    Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Unsupported predicate

    If I use the equivalent predicate

    NSPredicate *occurrenceIsNotExcludedPredicate = [NSPredicate predicateWithFormat: @"!(ANY excludedOccurrences.start == %@))", today];
    

    no exception is thrown, however the code does not work as expected: the occurrence for today, which should not be excluded, is instead excluded.

    I am not sure also how to test for the case excludedOccurrences == nil: the following predicate

    NSPredicate *nilPredicate = [NSPredicate predicateWithFormat: @"(excludedOccurrences == nil)"];
    

    causes at runtime the exception

    to-many key not allowed here

    However, since the excludedOccurrences relationship is optional, I also need to test if it is nil.

    How do I deal with this? Thank you in advance.

  • Simon Woodside
    Simon Woodside over 14 years
    your empty relationship solution crashes for me.
  • Ashley Clark
    Ashley Clark over 14 years
    Sorry about that, the predicate format has been fixed. I never bothered to test my assumption when this was posted, apparently no one else did either.
  • Ashley Clark
    Ashley Clark over 14 years
    I've corrected my answer, don't know what I was thinking when I wrote that. Mea culpa.
  • Joseph DeCarlo
    Joseph DeCarlo over 11 years
    It is unbelievable how long I have been looking for testing a one-to-many for an empty relationship. So glad you posted it here!
  • nicktones
    nicktones about 11 years
    Thanks for this. Got me out of a spot.
  • michael.zischka
    michael.zischka almost 10 years
    Thanks for that! Why does the documentation tell me to use 'array[SIZE]' instead, when it is not working?! Not mentioning the '@count' anywhere.
  • Andrew
    Andrew about 6 years
    It should be noted that the ALL modifier is not supported at all in predicates with Core Data when using the SQLite store type.