core data - Datos principales: ¿Query ID de objeto en un predicado?
nspredicate swift 4 (3)
Si bien la respuesta de @BarryWark es correcta cuando se trabaja con solicitudes de búsqueda, quiero escribir una advertencia a las personas que intentarán aplicar esta regla a un filtro de relaciones entre datos básicos.
En breve: si al filtrar a muchas relaciones usa un predicado y su matriz de objetos para la consulta IN es una matriz de ID de objeto, entonces debe usar self.objectID en su cadena de consulta como
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"(self.objectID IN %@)", arrayOfObjectIDs];
Debido a que usar just (self IN %@)
en el caso de filtrar a muchas relaciones dará como resultado resultados incorrectos, es solo un NSArray que evalúa predicados y no sabe nada sobre las cosas de NSManagedObjectID de Core Data.
He creado un código de prueba especial que muestra esto. Perdón por tantas líneas, pero valen la pena. Hay dos entidades: usuario y publicación, y el usuario tiene una relación de muchos llamada "publicaciones".
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);
Salida 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})")
Estoy obteniendo un conjunto de objetos de un almacén persistente de Core Data usando una solicitud de búsqueda y un predicado. Mi predicado actual simplemente verifica si un atributo es> = cierto valor. Todo esto funciona muy bien, excepto que quiero finalmente excluir cualquier objeto que se encuentre actualmente en una matriz.
Básicamente necesito poder excluir un conjunto de objetos, y la única forma en que creo que puedo hacer esto es poder obtener una lista de objectID
de mi matriz de objetos administrados y crear otra expresión en mi predicado para asegurarme de que cualquier los objetos devueltos no tienen el mismo objectID
. IE @"ANY records.objectID NOT IN %@", arrayOfObjectID
.
¿Cómo puedo hacer esto?
Solución Swift 3
Enfrenté la misma situación, por lo tanto, estoy publicando una solución rápida 3 a continuación
let predicate = NSPredicate(format:"NOT (self IN %@)",[arrayofNSManagedObjects])
Un predicado como
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"NOT (self IN %@)", arrayOfExcludedObjects];
donde la entidad de la solicitud de búsqueda es la entidad de objetos en la matriz, debe hacer lo que desee. Esto puede, por supuesto, combinarse con otras cláusulas en un solo predicado para una solicitud de obtención.
En general, las comparaciones de objetos (por ejemplo, self == %@
o self IN %@
) se comparan con objectID
en las consultas de Core Data. El argumento puede ser una instancia de NSManagedObject o una instancia de NSMangedObjectID
. Por lo tanto, el formato de predicado anterior podría tomar arrayOfExcludedObjects
o [arrayOfExcludedObjects valueForKey:@"objectID"]
como argumento.