Основные данные:Запросить идентификаторы объектов в предикате?

StackOverflow https://stackoverflow.com/questions/941357

  •  06-09-2019
  •  | 
  •  

Вопрос

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

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

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

Это было полезно?

Решение

Предикат типа

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

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

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

Другие советы

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

Вкратце:Если при фильтрации отношений ко многим вы используете предикат, а ваш массив объектов для запроса IN представляет собой массив идентификаторов объектов - тогда вам следует использовать 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})")

Решение Swift 3

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

let predicate = NSPredicate(format:"NOT (self IN %@)",[arrayofNSManagedObjects])
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top