Как правильно настроить NSP-предикат для отношения ко-многим при использовании Core Data? - PullRequest
22 голосов
/ 28 августа 2009

У меня есть базовая модель данных, в которой объект «Задача» включает в себя необязательное отношение «многие ко» «ExcludedDays» к объекту «ExcludedDay». Одним из свойств ExcludedDay является day, который является объектом NSDate. Сущность ExcludedDay имеет обратное обязательное отношение «один к одному» с сущностью Task.

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

Я начал пытаться

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

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

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

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

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

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

Ответы [ 2 ]

43 голосов
/ 15 сентября 2009

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

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

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

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

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

Если вы используете отношение ко-многим, конструкция предиката будет немного другой. Если вы хотите выбрать отделы, в которых хотя бы один из сотрудников имеет имя «Мэтью», например, вы используете ЛЮБОЙ оператор, как показано в следующем примере:

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

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

float salary = ... ;
NSPredicate *predicate = [NSPredicate predicateWithFormat:
    @"ALL employees.salary > %f", salary];
1 голос
/ 13 сентября 2009

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

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);

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

  1. Массив дней пуст
  2. Массив дня не содержит дату «сегодня»

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

  1. Массив day содержит слово «today».
    • Неважно, сколько объектов в массиве дня
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...