39 votes

Données de base : Interroger les objectIDs dans un prédicat ?

J'extrais un ensemble d'objets d'un magasin persistant Core Data à l'aide d'une requête d'extraction et d'un prédicat. Mon prédicat actuel vérifie simplement si un attribut est >= une certaine valeur. Tout cela fonctionne parfaitement, sauf que je veux finalement exclure tous les objets qui sont actuellement contenus dans un tableau.

J'ai essentiellement besoin de pouvoir exclure un ensemble d'objets, et la seule façon de le faire, à mon avis, est de pouvoir obtenir une liste des objets suivants objectID à partir de mon tableau d'objets gérés, et je crée une autre expression dans mon prédicat pour m'assurer que tous les objets renvoyés n'ont pas le même nom d'objet. objectID . I.E. @"ANY records.objectID NOT IN %@", arrayOfObjectID .

Comment puis-je le faire ?

75voto

Barry Wark Points 73462

Un prédicat comme

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

où l'entité de la requête de récupération est l'entité des objets dans le tableau, devrait faire ce que vous voulez. Cette clause peut, bien entendu, être combinée avec d'autres clauses dans un prédicat unique pour une requête de recherche.

En général, les comparaisons d'objets (par ex. self == %@ o self IN %@ ) comparer sur objectID dans les requêtes Core Data. L'argument peut être soit une instance de NSManagedObject ou un NSMangedObjectID instance. Ainsi, le format de prédicat ci-dessus pourrait prendre arrayOfExcludedObjects o [arrayOfExcludedObjects valueForKey:@"objectID"] comme argument.

1 votes

Merci pour votre aide. J'ai essayé d'utiliser [NSPredicate predicateWithFormat:@"self NOT IN %@", myArrayOfManagedObjects] mais j'ai obtenu une erreur "Unable to parse the format string "self NOT IN %@"" au moment de l'exécution. Avez-vous une idée ?

0 votes

Désolé, je me suis trompé en ne testant pas avant de poster. J'ai corrigé ma réponse (utiliser "NOT (self IN %@)" au lieu de "self NOT IN %@").

0 votes

Cela a bien fonctionné pour moi. Je l'ai utilisé pour filtrer en utilisant une logique complexe qui n'est pas prise en charge par SQL. Mais le predicateWithBlock ne fonctionne pas (pour des raisons raisonnables) sur SQL.

9voto

Stanislaw Points 670

Bien que la réponse de @BarryWark soit correcte lorsqu'on travaille avec des requêtes de récupération, je veux écrire un avertissement à l'intention des personnes qui essaieront d'appliquer cette règle à un filtrage des relations to-many de Core Data.

Brièvement : Si, lors du filtrage des relations de type "to-many", vous utilisez un prédicat et que votre tableau d'objets pour la requête IN est un tableau d'ID d'objets, alors vous devez utiliser la fonction self.objectID dans votre chaîne d'interrogation comme

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

Parce qu'en utilisant seulement (self IN %@) dans le cas du filtrage des relations to-many, les résultats seront incorrects. Il s'agit simplement d'un NSArray qui évalue des prédicats et qui ne connaît rien du système NSManagedObjectID de Core Data.

J'ai créé un code de test spécial qui le montre. Désolé pour les nombreuses lignes, mais elles en valent la peine. Il y a deux entités : User et Post et User a une relation to-many nommée "posts".

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

Sortie 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})")

4voto

Rajat Jain Points 494

Solution Swift 3

J'ai été confronté à la même situation, c'est pourquoi je publie ci-dessous une solution swift 3.

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X