2009-08-28 2 views
22

У меня есть модель базовых данных, в которой объект Task включает в себя необязательное отношение «многие-многие» ExcludedDays к объекту ExcludedDay. Одним из свойств ExcludedDay является день, который является объектом NSDate. Объект ExcludedDay имеет обратное обязательное к одному отношение к объекту Task.Как правильно настроить NSPredicate для отношений «многие» при использовании Core Data?

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

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

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

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

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

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

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

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

ответ

42

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

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

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

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

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

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

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

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

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

Возможно, вы знаете, как написать выражение с SUBQUERY с классами NSExpresion и NSComparisonPredicate? С вашего ответа, я решил мой вопрос: http://stackoverflow.com/questions/2006927/whats-better-way-to-build-nspredicate-with-to-many-deep-relationships Благодарности – Victor

+1

Большое вам спасибо за этот ответ, очень полезно. – Maria

1

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

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. В дневном массиве содержится «сегодня»
    • Это не имеет значения, сколько объектов в массиве дня являются
+1

к сожалению, это совершенно другая установка: мой контекст основывается на основных данных и iPhone SDK 3,0 или 3,1. Похоже, что структура Core Data неправильно обрабатывает предикаты при соблюдении отношений «многие». Я уже подал ошибку, и инженеры Apple работают над этим, но ответа от них все равно нет. –

+1

Тогда это действительно проблема с ретрансляцией Core Data, поскольку с использованием того же предиката, но без Core Data, он работает правильно (как видно из моей попытки подражать тому же (связанному с Foumdation) контексту) – Joost

+1

помог мне в 2011 году :) +1 –

Смежные вопросы