2010-01-08 9 views
11

Ich habe eine NSArrayController, companiesController gebunden an eine oberste Ebene Core Data-Entität, Companies.Verwenden von NSPredicate mit Core Data für tiefe Beziehungen

Ein Company hat viele Department, und ein Department hat viele Employee; Diese werden durch die 1-zu-viele-Beziehungen departments und employees dargestellt.

Basierend auf dem Attribute salary ein Employee ich dachte ich, das dynamisch in einem UI genannten Verfahren zur Filterung basierend auf Gehalt tun könnte:

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

Ach, gibt dies mir den Fehler: -[NSCFSet compare:]: unrecognized selector sent to instance.

Antwort

17

Mehrere zu viele Schlüssel sind in diesem Fall nicht zulässig.

Stattdessen könnten Sie Folgendes tun:

  1. das Datenmodell ändern „Filter“ Flag (Boolean) Attribut an die Abteilung Einheit durch Zugabe.
  2. Erstellen Sie eine Methode, um alle Department-Objekte abzurufen, das Filter-Flag für die Abteilungen, die die Kriterien der zweiten Hälfte Ihres Prädikats erfüllen, auf YES zu setzen, das Filter-Flag für die anderen Abteilungen auf NO zu setzen und zu speichern.
  3. Verwenden Sie das Filterkennzeichen im Firmenprädikat.

Änderungen am Code (Schritt 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]; 

und die neue Methode (Schritt 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

Danke, das funktioniert. Scheint wie ein Workaround, aber das sind nur die Probleme von Core Data. – raheel

+0

Ich würde annehmen, dass es etwas damit zu tun hat, wie Core Data das NSPredate in SQLite-Anweisungen übersetzt. Die Syntax ist mehrdeutig: meinst du BELIEBIGE oder ALLE Mitarbeiter in einer bestimmten Abteilung. Ich bin auch ein SQL-Neuling, aber ich schätze, selbst wenn Ihr ursprüngliches Prädikat in einer einfachen SQL-Anweisung erledigt werden könnte, würde es eine potentiell große Verknüpfung erfordern, die Apple zu speicher- oder leistungsintensiv für einen einzelnen Abruf hält. – gerry3

+0

Auch ich habe eine ganze Weile damit verbracht, so ein Up-Vote zu schätzen :-). – gerry3

10

Sie auch diese Unterabfragen tun könnten.

Holen Sie sich alle Abteilungen. Die ‚von‘ Beziehung ist die Umkehrung der Gesellschaft zu viele Abteilungen:

-(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]; 
} 

Oder, wenn Sie mehr Unternehmen haben und wollen nur die Unternehmen, die einen Mitarbeiter mit einem Gehalt ‚höher als‘ einen gewissen Betrag haben. Eine Unterabfrage basierend auf dem Ergebnis einer Unterabfrage

-(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

Funktioniert das mit einem SQLite-Speicher für Mac OS und iOS? Aus der Apple-Dokumentation (aus der iOS 5.0-Bibliothek: Core Data Programming Guide> Beständige Speicherfunktionen> Prädikate abrufen und Sortierdeskriptoren - kann für Mac OS anders sein): "Es gibt zusätzliche Einschränkungen für die Prädikate, die Sie mit dem verwenden können SQLite-Speicher: Sie können "beliebige" SQL-Abfragen nicht unbedingt in Prädikaten übersetzen." – Dalmazio

+0

Weiß nicht. Probieren Sie es aus :) – andershqst

+0

Bestes reales Welt Prädikat SubQuery Beispiel Ich bin noch –

Verwandte Themen