2010-01-08 14 views
11

Tengo un NSArrayController, companiesController vinculado a una entidad de datos principales de nivel superior, Companies.Uso de NSPredicate con Core Data para relaciones profundas

Un Company tiene muchas Department 's, y una Department tiene muchas Employee; estos están representados por las relaciones 1 a muchos, departments y employees.

Basado en el atributo de un salaryEmployee pensé que podía hacer dinámicamente esto para el filtrado basado en el salario dentro de un método de interfaz de usuario llamada:

NSPredicate *predicate = [NSPredicate predicateWithFormat:@"ANY departments.employees.salary < %@", [NSNumber numberWithInt:23000]]; 
[companiesController setFilterPredicate:predicate]; 

Por desgracia, esto me da el error: -[NSCFSet compare:]: unrecognized selector sent to instance.

Respuesta

17

En este caso, no se permiten varias teclas múltiples.

En su lugar, podría hacer lo siguiente:

  1. Modificar el modelo de datos mediante la adición de un atributo de "filtro" de la bandera (booleano) a la entidad Departamento.
  2. Cree un método para: recuperar todos los objetos Departamento, establecer el indicador de filtro en SÍ para los departamentos que cumplen los criterios de la segunda mitad de su predicado, establecer el indicador de filtro en NO para los otros departamentos y guardar.
  3. Utilice el indicador de filtro en el predicado de compañía.

cambios de código (paso 3):

//NSPredicate *predicate = [NSPredicate predicateWithFormat:@"ANY departments.employees.salary < %@", [NSNumber numberWithInt:23000]]; 
    [self setDeptFilter:23000]; 
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"ANY depts.filter == YES"]; 
    [companiesController setFilterPredicate:predicate]; 

y el nuevo método (paso 2):

- (void)setDeptFilter:(NSUInteger)salary { 
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init]; 

    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Department" inManagedObjectContext:self.managedObjectContext]; 
    [fetchRequest setEntity:entity]; 

    NSError *error = nil; 

    // fetch all Department objects 
    NSArray *array = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error]; 

    [fetchRequest release]; 

    if (error) { 
     NSLog(@"Error fetching Departments %@, %@", error, [error userInfo]); 
     abort(); 
    } 

    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"ANY emps.salary < %@",[NSNumber numberWithInteger:salary]]; 
    NSArray *filterArray = [array filteredArrayUsingPredicate:predicate]; 

    // set filter flag to YES for the departments that meet the criteria 
    for (Department *dep in filterArray) { 
     dep.filter = [NSNumber numberWithBool:YES]; 
    } 

    NSMutableArray *diffArray = [array mutableCopy]; 
    [diffArray removeObjectsInArray:filterArray]; 

    // set filter flag to NO for the departments that do NOT meet the criteria 
    for (Department *dep in diffArray) { 
     dep.filter = [NSNumber numberWithBool:NO]; 
    } 

    [diffArray release]; 

    // save 
    if ([self.managedObjectContext hasChanges] && ![self.managedObjectContext save:&error]) { 
     NSLog(@"Unresolved error %@, %@", error, [error userInfo]); 
     abort(); 
    } 
} 
+0

Gracias, esto funciona. Parece una solución, pero supongo que solo se trata de problemas de Core Data. – raheel

+0

Supongo que tiene algo que ver con cómo Core Data traduce NSPredicate en declaraciones SQLite. La sintaxis es ambigua: ¿se refiere a CUALQUIERA o TODOS los empleados en un departamento en particular? Además, soy un principiante de SQL, pero supongo que incluso si tu predicado original se puede hacer en una declaración SQL directa, requeriría una unión potencialmente grande que Apple podría considerar demasiado intensiva en memoria o rendimiento para una búsqueda simple. – gerry3

+0

Además, pasé bastante tiempo en esto, por lo que se agradecería una votación positiva :-). – gerry3

10

También puede hacerlo mediante subconsultas.

Obtener todos los departamentos. El 'de la' relación es la inversa de los departamentos de la empresa-a-muchos:

-(void)printDepartmentsWithSalaryHigherThan:(int)salary inContext:(NSManagedObjectContext *)context {  
    NSFetchRequest *request = [[NSFetchRequest alloc ]init]; 
    request.entity = [NSEntityDescription entityForName:@"Department" inManagedObjectContext:context]; 
    request.predicate = [NSPredicate predicateWithFormat:@"SUBQUERY(employees, $emp, $emp.salary > %@)[email protected] > 0", [NSNumber numberWithInt:salary]]; 

    for(Department *dep in [context executeFetchRequest:request error:nil]){ 
     NSLog(@"Department: %@", dep.depName); 
     NSLog(@"in Company: %@", dep.of.compName); 
    } 
    [request release]; 
} 

O, si usted tiene más compañías y sólo quiere las empresas que tienen un empleado con un sueldo 'mayor que' una cierta cantidad. Una subconsulta basada en el resultado de una subconsulta

-(void)printCompaniesWithHigherSalaryThan:(int)salary inContext:(NSManagedObjectContext *)context { 
    NSFetchRequest *request = [[NSFetchRequest alloc ]init]; 
    request.entity = [NSEntityDescription entityForName:@"Company" inManagedObjectContext:context]; 
    request.predicate = [NSPredicate predicateWithFormat:@"SUBQUERY(departments, $dep, SUBQUERY($dep.employees,$emp,$emp.salary > %@)[email protected] > 0)[email protected] > 0", [NSNumber numberWithInt:salary]]; 

    for(Company *c in [context executeFetchRequest:request error:nil]){ 
     NSLog(@"Company: %@", c.compName); 
    } 
    [request release]; 
} 
+0

¿Funciona esto con una tienda SQLite para Mac OS e iOS? De la documentación de Apple (de la biblioteca iOS 5.0: Guía de programación de datos básicos> Características persistentes de la tienda> Obtener predicciones y ordenar descriptores: puede ser diferente para Mac OS): "Hay restricciones adicionales en los predicados que puede usar con el Tienda SQLite: No necesariamente puede traducir consultas SQL "arbitrarias" en predicados." – Dalmazio

+0

No lo sé. Pruébalo :) – andershqst

+0

Mejor predicado del mundo real Ejemplo de SubQuery Me encontré con –

Cuestiones relacionadas