Основные данные: запрос идентификаторов объектов в предикате? - PullRequest
36 голосов
/ 02 июня 2009

Я получаю набор объектов из постоянного хранилища Core Data, используя запрос на выборку и предикат. Мой текущий предикат просто проверяет, является ли атрибут> = определенным значением. Все это прекрасно работает, за исключением того, что я хочу окончательно исключить любые объекты, которые в данный момент содержатся в массиве.

Мне нужно исключить набор объектов, и я думаю, что единственный способ сделать это - получить список objectID из массива управляемых объектов и создать другое выражение предикат, чтобы гарантировать, что любые возвращаемые объекты не имеют одинаковые objectID. И.Е. @"ANY records.objectID NOT IN %@", arrayOfObjectID.

Как я могу это сделать?

Ответы [ 3 ]

69 голосов
/ 02 июня 2009

Предикат, подобный

NSPredicate *predicate = [NSPredicate predicateWithFormat:@"NOT (self IN %@)", arrayOfExcludedObjects];

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

Как правило, сравнения объектов (например, self == %@ или self IN %@) сравниваются с objectID в запросах базовых данных. Аргумент может быть экземпляром NSManagedObject или или NSMangedObjectID. Таким образом, приведенный выше формат предиката может принимать arrayOfExcludedObjects или [arrayOfExcludedObjects valueForKey:@"objectID"] в качестве аргумента.

9 голосов
/ 26 августа 2013

Хотя ответ @ BarryWark является правильным при работе с запросами на выборку, я хочу написать предупреждение тем людям, которые попытаются применить это правило к фильтрации основных данных для многих отношений.

Коротко: если при фильтрации по многим отношениям вы используете предикат, а ваш массив объектов для запроса IN является массивом objectID, - вам следует использовать self.objectID в строке запроса, например

NSPredicate *predicate = [NSPredicate predicateWithFormat:@"(self.objectID IN %@)", arrayOfObjectIDs];

Поскольку использование только (self IN %@) в случае фильтрации ко многим отношениям приведет к неверным результатам - это просто NSArray, который оценивает предикаты, и ничего не знает о компоненте NSManagedObjectID Core Data.

Я создал специальный тестовый код, показывающий это. Извините за столько строк, но они того стоят. Существует два объекта: Пользователь и Сообщение, и Пользователь имеет отношение ко многим, называемое "сообщения".

User *user = [NSEntityDescription insertNewObjectForEntityForName:NSStringFromClass([User class]) inManagedObjectContext:managedObjectContext()];

Post *post = [NSEntityDescription insertNewObjectForEntityForName:NSStringFromClass([Post class]) inManagedObjectContext:managedObjectContext()];

[user addPostsObject:post];

[managedObjectContext() save:nil];

// 1. Both filtered relationship array and fetch result are correct!
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"(self IN %@)", @[ post ]];

NSSet *filteredRelationship = [user.posts filteredSetUsingPredicate:predicate];

NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:@"Post"];
NSArray *fetchResult = [managedObjectContext() executeFetchRequest:fetchRequest error:nil];

NSLog(@"\n\n\nPredicate: %@", predicate);
NSLog(@"filteredRelationship: %@", filteredRelationship);
NSLog(@"fetchResult: %@", fetchResult);

// 2. Filtered relationship array is empty (wrong), fetch result is correct, !
predicate = [NSPredicate predicateWithFormat:@"(self IN %@)", @[ post.objectID ]];

filteredRelationship = [user.posts filteredSetUsingPredicate:predicate];

fetchRequest = [[NSFetchRequest alloc] initWithEntityName:@"Post"];
fetchResult = [managedObjectContext() executeFetchRequest:fetchRequest error:nil];

NSLog(@"\n\n\nPredicate: %@", predicate);
NSLog(@"filteredRelationship: %@", filteredRelationship);
NSLog(@"fetchResult: %@", fetchResult);

// 3. Filtered relationship array is empty (wrong), fetch result is correct
predicate = [NSPredicate predicateWithFormat:@"(self.objectID IN %@)", @[ post ]];

filteredRelationship = [user.posts filteredSetUsingPredicate:predicate];

fetchRequest = [[NSFetchRequest alloc] initWithEntityName:@"Post"];
fetchResult = [managedObjectContext() executeFetchRequest:fetchRequest error:nil];

NSLog(@"\n\n\nPredicate: %@", predicate);
NSLog(@"filteredRelationship: %@", filteredRelationship);
NSLog(@"fetchResult: %@", fetchResult);

// 4. Filtered relationship array is correct, fetch result is correct
predicate = [NSPredicate predicateWithFormat:@"(self.objectID IN %@)", @[ post.objectID ]];

filteredRelationship = [user.posts filteredSetUsingPredicate:predicate];

fetchRequest = [[NSFetchRequest alloc] initWithEntityName:@"Post"];
fetchResult = [managedObjectContext() executeFetchRequest:fetchRequest error:nil];

NSLog(@"\n\n\nPredicate: %@", predicate);
NSLog(@"filteredRelationship: %@", filteredRelationship);
NSLog(@"fetchResult: %@", fetchResult);

Выход TLDR

<redacted> Predicate: SELF IN {<Post: 0x2a04f10> (entity: Post; id: 0x2a56c40 <x-coredata://9D07BF41-2DC0-42C1-9DD8-6082A00E7BEB/Post/p1> ; data: { content = nil; title = nil; user = "0x2af2a20 <x-coredata://9D07BF41-2DC0-42C1-9DD8-6082A00E7BEB/User/p1>"; })}

<redacted> filteredRelationship: {(<Post: 0x2a04f10> (entity: Post; id: 0x2a56c40 <x-coredata://9D07BF41-2DC0-42C1-9DD8-6082A00E7BEB/Post/p1> ; data: { content = nil; title = nil; user = "0x2af2a20 <x-coredata://9D07BF41-2DC0-42C1-9DD8-6082A00E7BEB/User/p1>"; }) )}

<redacted> fetchResult: ("<Post: 0x2a04f10> (entity: Post; id: 0x2a56c40 <x-coredata://9D07BF41-2DC0-42C1-9DD8-6082A00E7BEB/Post/p1> ; data: {\n    content = nil;\n    title = nil;\n    user = \"0x2af2a20 <x-coredata://9D07BF41-2DC0-42C1-9DD8-6082A00E7BEB/User/p1>\";\n})")

<redacted> Predicate: SELF IN {0x2a56c40 <x-coredata://9D07BF41-2DC0-42C1-9DD8-6082A00E7BEB/Post/p1>}

<redacted> filteredRelationship: {()}

<redacted> fetchResult: ("<Post: 0x2a04f10> (entity: Post; id: 0x2a56c40 <x-coredata://9D07BF41-2DC0-42C1-9DD8-6082A00E7BEB/Post/p1> ; data: {\n    content = nil;\n    title = nil;\n    user = \"0x2af2a20 <x-coredata://9D07BF41-2DC0-42C1-9DD8-6082A00E7BEB/User/p1>\";\n})")

<redacted> Predicate: objectID IN {<Post: 0x2a04f10> (entity: Post; id: 0x2a56c40 <x-coredata://9D07BF41-2DC0-42C1-9DD8-6082A00E7BEB/Post/p1> ; data: { content = nil; title = nil; user = "0x2af2a20 <x-coredata://9D07BF41-2DC0-42C1-9DD8-6082A00E7BEB/User/p1>";})}

<redacted> filteredRelationship: {()}

<redacted> fetchResult: ("<Post: 0x2a04f10> (entity: Post; id: 0x2a56c40 <x-coredata://9D07BF41-2DC0-42C1-9DD8-6082A00E7BEB/Post/p1> ; data: {\n    content = nil;\n    title = nil;\n    user = \"0x2af2a20 <x-coredata://9D07BF41-2DC0-42C1-9DD8-6082A00E7BEB/User/p1>\";\n})")

<redacted> Predicate: objectID IN {0x2a56c40 <x-coredata://9D07BF41-2DC0-42C1-9DD8-6082A00E7BEB/Post/p1>} 

<redacted> filteredRelationship: {(<Post: 0x2a04f10> (entity: Post; id: 0x2a56c40 <x-coredata://9D07BF41-2DC0-42C1-9DD8-6082A00E7BEB/Post/p1> ; data: { content = nil; title = nil; user = "0x2af2a20 <x-coredata://9D07BF41-2DC0-42C1-9DD8-6082A00E7BEB/User/p1>";}))}

<redacted> fetchResult: ("<Post: 0x2a04f10> (entity: Post; id: 0x2a56c40 <x-coredata://9D07BF41-2DC0-42C1-9DD8-6082A00E7BEB/Post/p1> ; data: {\n    content = nil;\n    title = nil;\n    user = \"0x2af2a20 <x-coredata://9D07BF41-2DC0-42C1-9DD8-6082A00E7BEB/User/p1>\";\n})")
1 голос
/ 26 июля 2017

раствор Swift 3

Я столкнулся с такой же ситуацией, поэтому я публикую быстрое решение 3 ниже

let predicate = NSPredicate(format:"NOT (self IN %@)",[arrayofNSManagedObjects])
...