ios core-data nspredicate

ios - nsfetchrequest swift 4



Combinando ''AND'' y ''OR'' Condition en NSPredicate (3)

De vuelta, necesito más ayuda para construir mis NSPredicates :(

Category { name:string subs<-->>SubCategory } SubCategory { name:string numbervalue:NSNumber }

Me gustaría saber cómo crear un predicado con AND y OR .

Por ejemplo, me gustaría devolver cada Categoría con el nombre == "nombre_categoría" que también tiene una subcategoría con un valor numérico de "valorA" O "valorB".

Probé todas las combinaciones posibles de constructores de predicados que pude encontrar, pero simplemente no puedo hacer que funcione.

Este es mi mejor intento hasta ahora.

NSPredicate *predicate=[NSPredicate predicateWithFormat@"(name== %@) AND (ANY subs.numbervalue==%@ OR ANY subs.numbervalue==%@)", @"aname", value1, value2];

Editar 1

Segundo intento. El filtrado en el ''valor numérico'' aún no está funcionando.

NSNumber valueA=[NSNumber numberWithInt:20]; NSNumber valueA=[NSNumber numberWithInt:90]; NSArray *arr=[NSArray arrayWithObject:valueA,valueB,nil]; predicate=[NSPredicate predicateWithFormat:@"(name==%@)AND(ANY subs.numbervalue IN %@)",@"aname",arr];

Editar 2

Intenté filtrar solo por numberValue y dejé el nombre por completo.

1) al utilizar esto, se devuelve el conjunto completo aunque solo 1 elemento del conjunto tenga el valor.

predicate=[NSPredicate predicateWithFormat:@"(ANY subs.numbervalue IN %@)",arr];

2) El uso de esto da como resultado el mismo problema, cada artículo en el conjunto que se devuelve, incluso si solo uno de ellos coincide.

predicate=[NSPredicate predicateWithFormat:@"((SUBQUERY(subs, $x, $x.numbervalue == %@ or $x.numbervalue == %@).@count > 0)", value1, value2];

Usar también la versión más simple da como resultado el mismo problema ... No me di cuenta de esto antes.

NSPredicate *predicate=[NSPredicate predicateWithFormat@"(ANY subs.numbervalue==%@ ,valueA];

Así que creo que tengo mi problema reducido.

La categoría es una entidad. SubCategory es una Entidad.

La categoría tiene una relación de uno a muchos con SubCategory y se representa como un NSSet de SubCategory.

Cada SubCategory tiene un atributo llamado numbervalue.

Editar 3

Para probar, tengo 2 categorías. Ambas categorías tienen 10 subs, cada uno con un valor numérico de 1 -10;

Con este código, se devuelven ambas categorías junto con los 10 subs para cada una.

El resultado esperado es la devolución de ambas categorías, cada una con solo 2 subs.

He trazado todos mis objetos y los datos son correctos. El problema es que no puedo devolver una categoría que tenga subs filtrados.

NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init]; NSManagedObjectContext *context=[[DataSource sharedDataSource]managedObjectContext]; NSEntityDescription *entity = [NSEntityDescription entityForName:@"Category" inManagedObjectContext:context]; [fetchRequest setEntity:entity]; [fetchRequest setFetchBatchSize:20]; NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES]; NSArray *sortDescriptors = [NSArray arrayWithObjects:sortDescriptor, nil]; NSPredicate *predicate; NSNumber *a=[NSNumber numberWithFloat:1]; NSNumber *b=[NSNumber numberWithFloat:2]; predicate=[NSPredicate predicateWithFormat:@"(SUBQUERY(subs,$x,$x.numbervalue==%@ or $x.numbervalue==%@).@count> 0)",a,b]; [fetchRequest setPredicate:predicate]; [fetchRequest setSortDescriptors:sortDescriptors]; NSError *error = nil; [NSFetchedResultsContoller deleteCacheWithName:nil]; NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:context sectionNameKeyPath:@"name" cacheName:@"Master"]; aFetchedResultsController.delegate = self; self.fetchedResultsController = aFetchedResultsController; if (![self.fetchedResultsController performFetch:&error]) { NSLog(@"Unresolved error %@, %@", error, [error userInfo]); abort(); }


Además de la respuesta de @ Stuart, puede usar NSCompoundPredicate para sus operaciones OR & AND de esta manera.

Obj-C - O

// OR Condition // NSPredicate *predicate1 = [NSPredicate predicateWithFormat:@"X == 1"]; NSPredicate *predicate2 = [NSPredicate predicateWithFormat:@"X == 2"]; NSPredicate *predicate = [NSCompoundPredicate orPredicateWithSubpredicates:@[predicate1, predicate2]];

Obj-C - Y

NSPredicate *predicate1 = [NSPredicate predicateWithFormat:@"X == 1"]; NSPredicate *predicate2 = [NSPredicate predicateWithFormat:@"X == 2"]; NSPredicate *predicate = [NSCompoundPredicate andPredicateWithSubpredicates:@[predicate1, predicate2]];

Swift - O

let predicate1:NSPredicate = NSPredicate(format: "X == 1") let predicate2:NSPredicate = NSPredicate(format: "Y == 2") let predicate:NSPredicate = NSCompoundPredicate(orPredicateWithSubpredicates: [predicate1,predicate2] )

Swift - AND

let predicate1:NSPredicate = NSPredicate(format: "X == 1") let predicate2:NSPredicate = NSPredicate(format: "Y == 2") let predicate:NSPredicate = NSCompoundPredicate(andPredicateWithSubpredicates: [predicate1,predicate2] )

Swift 3 - O

let predicate1 = NSPredicate(format: "X == 1") let predicate2 = NSPredicate(format: "Y == 2") let predicateCompound = NSCompoundPredicate.init(type: .or, subpredicates: [predicate1,predicate2])

Swift 3 - AND

let predicate1 = NSPredicate(format: "X == 1") let predicate2 = NSPredicate(format: "Y == 2") let predicateCompound = NSCompoundPredicate.init(type: .and, subpredicates: [predicate1,predicate2])


Haré lo siguiente usando SUBQUERY .

[NSPredicate predicateWithFormat@"(name == %@) AND (SUBQUERY(subs, $x, $x.numbervalue == %@ or $x.numbervalue == %@).@count > 0)", @"aname", value1, value2];

Pruébalo y házmelo saber.

Otra solución podría ser tomar los subs completos de la colección y luego filtrar el conjunto recuperado con un predicado para verificar si los elementos coinciden con value1 o value2 .

Espero eso ayude.

Editar

Si sigues la sugerencia de Eimantas, asegúrate de crear la matriz correcta:

NSNumber valueA = [NSNumber numberWithInt:20]; NSNumber valueB = [NSNumber numberWithInt:90]; NSArray *arr = [NSArray arrayWithObjects:valueA, valueB, nil];