Подтвердить что ты не робот

Как правильно настроить NSPredicate для отношения "многие" при использовании Core Data?

У меня есть модель Core Data, в которой объект Task включает в себя необязательное отношение to-many ExcludedDays к объекту ExcludedDay. Одним из свойств ExcludedDay является день, который является объектом NSDate. Объект ExcludedDay имеет обратное обязательное отношение к одному объекту Task.

Чтобы получить задания в течение указанного дня, мне нужно убедиться, что указанный день не отображается как свойство day любого объекта ExludedDay.

Я начал пробовать

NSPredicate *dayIsNotExcludedPredicate = [NSPredicate predicateWithFormat: @"ALL excludedDays.day != %@", today];

Однако, несмотря на то, что говорится в документации, ALL не работает, и приложение выдает исключение: Завершение приложения из-за неотображенного исключения 'NSInvalidArgumentException, reason:' Неподдерживаемый предикат.

После публикации того же вопроса на этом форуме, я смог разработать следующий предикат с помощью разных людей:

NSPredicate * dayIsNotExcludedPredicate = [NSPredicate predicateWithFormat: @"[email protected] == 0 || ([email protected] > 0 && NONE excludedDays.day == %@))", today];

Пока это работало, я только что обнаружил, что это работает только тогда, когда объект ExcludedDay содержит ТОЛЬКО один день. Как только объект ExcludedDay содержит более одного дня для одной задачи, этот предикат перестает работать. В результате задача выбирается в течение дня, даже если день появляется как день в объекте ExcludedDay, что, конечно, неверно. Проблема не связана с тем, что день свойства является объектом NSDate: заменяя день соответствующей NSString или эквивалентно целому числу, я по-прежнему сталкиваюсь с той же проблемой и неправильным поведением.

Каков правильный способ реализации предиката в этом случае? Может быть, это ошибка, связанная с любым агрегирующим оператором при использовании основных данных? Заранее спасибо, теперь это сводит меня с ума.

4b9b3361

Ответ 1

Оказывается, это еще одна проблема с отсутствующей и/или несогласованной документацией.

Правильный предикат в этом случае следующий:

[NSPredicate predicateWithFormat:@"([email protected] == 0) OR (0 == SUBQUERY(excludedOccurrences, $sub, $sub.day == %@)[email protected])", today]

В предикате подзапрос используется для проверки того, равна ли количество связанных исключенных экземпляров с датой, соответствующей вашей дате тестирования, равной нулю. Однако документация вводит в заблуждение. Вот что говорится в руководстве по программированию Predicate относительно использования предикатов в сочетании со многими отношениями.

Использование предикатов с отношениями

Если вы используете отношение "ко многим", построение предиката несколько отличается. Если вы хотите получить департаменты, в которых, по крайней мере, один из сотрудников имеет имя "Matthew", например, вы используете оператор ANY, как показано в следующем примере:

NSPredicate *predicate = [NSPredicate predicateWithFormat:
    @"ANY employees.firstName like 'Matthew'"];

Если вы хотите найти отделы, в которых всем сотрудникам выплачивается более определенной суммы, вы используете оператор ALL, как показано в следующем примере:

float salary = ... ;
NSPredicate *predicate = [NSPredicate predicateWithFormat:
    @"ALL employees.salary > %f", salary];

Ответ 2

Очень любопытно, как решить эту проблему. Я настраиваю небольшой проект и создаю контекст, который вы используете.

NSDate *today = [NSDate date];
NSMutableArray *objects = [NSMutableArray array];

{
    NSArray *day = [NSArray arrayWithObjects:today, [today dateByAddingTimeInterval:20.0f], nil];
    NSDictionary *excludedDay = [NSDictionary dictionaryWithObject:day forKey:@"day"];
    NSDictionary *object = [NSDictionary dictionaryWithObject:excludedDay forKey:@"excludedDay"];

    [objects addObject:object];
}

{
    NSArray *day = [NSArray arrayWithObjects:[today dateByAddingTimeInterval:20.0f], nil];
    NSDictionary *excludedDay = [NSDictionary dictionaryWithObject:day forKey:@"day"];
    NSDictionary *object = [NSDictionary dictionaryWithObject:excludedDay forKey:@"excludedDay"];

    [objects addObject:object];
}


NSPredicate *predicate = [NSPredicate predicateWithFormat:@"NONE excludedDay.day == %@", today];
NSArray *filtered = [objects filteredArrayUsingPredicate:predicate];

NSLog(@"%@", filtered);

Это дает объект, когда:

  • Дневной массив пуст
  • В массиве "День" нет "сегодняшней" даты

Это не дает объект, если:

  • В дневном массиве содержится "сегодня",
    • Неважно, сколько объектов в массиве day