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];
Otra opción es usar un NSCompoundPredicate (note andPredicateWithSubpredicates hace un AND pero hay algunas opciones para usar, esto debería ser mucho más eficiente que hacer 2 búsquedas)