Ответ 1
Это определенный ответ:
[NSPredicate predicateWithFormat:@"SUBQUERY(entryTags, $tag, $tag IN %@)[email protected] = %d", selectedTags, [selectedTags count]];
В-Е-А-У-Т-I-F-U-L.
Благодаря Дейву ДеЛонгу.
На основе модели данных ниже
И на основе ввода пользователем я создаю NSSet управляемых объектов объекта тега, называемых selectedTags.
[NSPredicate predicateWithFormat:@"ANY entryTags IN %@", selectedTags];
... это приведет к возврату любой записи с по крайней мере одним элементом ввода, который находится в выбранном наборе тагов.
Я хочу что-то вроде:
[NSPredicate predicateWithFormat:@"ALL entryTags IN %@", selectedTags];
... Обратите внимание, что единственным изменением является "ЛЮБОЙ" для "ВСЕ". Это иллюстрирует то, что я хочу, но не работает.
Чтобы сформулировать результат, я ожидаю:
Я ищу решение, которое будет возвращать только те записи, которые entryTags находятся в списке selectedTags (но в то же время, если это возможно, не обязательно наоборот).
Для дополнительной иллюстрации:
(тег) мама
(Тег) папа
(тег) Подарки
(запись) она она..... (тег) мама
(вход), он является............ (тег) папа
(вход) подарки для мамы... (метки:) мама, подарки
(вход) подарки для папы..... (теги:) папа, подарки
Если selectedTags содержит "mom" и "gifts", тогда появится запись "подарки для папы", так как у нее есть тег "подарки". Я бы предпочел, чтобы он не показывал:)
Это определенный ответ:
[NSPredicate predicateWithFormat:@"SUBQUERY(entryTags, $tag, $tag IN %@)[email protected] = %d", selectedTags, [selectedTags count]];
В-Е-А-У-Т-I-F-U-L.
Благодаря Дейву ДеЛонгу.
Как насчет использования сложного предиката? Насколько я понимаю, вы хотите вернуть все записи, которые соответствуют списку тегов, а не только любому из них. Один из подходов заключался бы в создании предиката для каждого тега, затем И их вместе с использованием сложного предиката.
NSMutableArray *predicates = [[NSMutableArray alloc] init];
for (Tag *tag in selectedTags) {
[predicates addObject:[NSPredicate predicateWithFormat:@"ANY entryTags.tagName MATCHES %@", tag.tagName]];
}
NSPredicate *compoundPredicate = [NSCompoundPredicate andPredicateWithSubpredicates:predicates];
Это должно достичь желаемого. Затем просто установите этот предикат по вашему запросу.
Вы не можете делать то, что хотите, с помощью предиката.
Операторы ANY
и ALL
применяются к проверяемой сущности (в данном случае Entry
), а не к содержимому коллекции (selectedTags
). Любой оператор возвращает объект Entry
, который соответствует любому одному элементу коллекции. Оператор ANY
вернет первое совпадение, которое он найдет, пока оператор ALL
вернет все совпадения. В любом случае они не возвращают запись, которая соответствует каждому элементу в предоставленной коллекции.
(Также похоже, что вы пытаетесь использовать фактические объекты Tag
в selectedTags
. Это, скорее всего, не сработает либо потому, что объект сравнивается с классами без специальных методов сравнения, как правило, терпит неудачу. сравнить атрибуты в предикатах.)
Поскольку у вас уже есть объекты Tag
, которые вы хотите, чтобы найти связанные с кандидатом объекты Entity
, вам просто нужно пройти связь Tag.taggedEntries
. Затем вам нужно найти пересечение всех наборов объекта Entity
, чтобы найти только те объекты Entity
, которые связаны с каждым выбранным Tag
bject. Поскольку нет оператора пересечений, вам нужен цикл.
if ([selectedEntries count]>=2) {
NSMutableSet *intersectEntries=[[NSMutableSet alloc] initWithCapacity:1];
for (int i=1; i<[selectedTags count]; i++) {
if ([intersectEntries count]==0) {
[intersectEntries unionSet:[[selectedEntries objectAtIndex:(i-1)] valueForKey:@"taggedEntries"]];
}
[intersectEntries intersectSet:[[selectedEntries objectAtIndex:i] valueForKey:@"taggedEntries"]];
}
}
(Примечание: я не тестировал это, но он должен работать.)
Теперь intersectEntries
должен содержать только те объекты Entry
, которые связаны с каждым выбранным тегом.
Я понял, что могу дать что-то здесь для руководства, которое я получил ранее. Используя код TechZen, я смог придумать следующее - и для меня ценная часть кода:
- (NSArray *)unionSetOfObjectsForObjects:(NSArray *)objects {
NSMutableSet *unionSetOfObjects = [NSMutableSet set];
if (objects.count)
[unionSetOfObjects unionSet:[[objects objectAtIndex:0] valueForKey:@"key"]];
//unionSetOfObjects = [[objects objectAtIndex:0] valueForKey:@"key"];
if (objects.count > 1)
for (id object in objects)
[unionSetOfObjects intersectSet:[object valueForKey:@"key"]];
return unionSetOfObjects.allObjects;
}
Если не сразу видно, что делает этот код:
Он собирает все значения (в моих объектах) для ключа key
для всех объектов, представленных в массиве objects
.
Этот код просто... на вкус хороший, не так ли?
Самый простой способ сделать это:
[NSPredicate predicateWithFormat:@"entryTags IN %@", selectedTags];
Вам не нужно предложение ALL. Это также описано здесь:
Руководство по программированию предикатов
И как вы можете видеть в этом сообщении, пользователь делает это успешно (прочитайте комментарии к исходному вопросу)