Using NSPredicate with Core Data for deep relationships

前端 未结 2 727
无人及你
无人及你 2020-12-28 21:20

I have an NSArrayController, companiesController bound to a top level Core Data entity, Companies.

A Company has many D

相关标签:
2条回答
  • 2020-12-28 21:33

    You could also do this using subqueries.

    Get all departments. The 'of' relationship is the inverse of company to-many departments:

    -(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 > %@ ).@count > 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];
    }
    

    Or, if you have more companies and just want the companies that have an employee with a salary 'higher than' some amount. A subquery based on the result of a subquery

    -(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 > %@).@count > 0 ).@count > 0", [NSNumber numberWithInt:salary]];
    
        for(Company *c in [context executeFetchRequest:request error:nil]){
            NSLog(@"Company: %@", c.compName);
        }
        [request release];
    }
    
    0 讨论(0)
  • 2020-12-28 21:51

    Multiple to-many keys are not allowed in this case.

    Instead, you could do the following:

    1. Modify the data model by adding a "filter" flag (Boolean) attribute to the Department entity.
    2. Create a method to: fetch all the Department objects, set the filter flag to YES for the departments that meet the criteria of the second half of your predicate, set the filter flag to NO for the other departments, and save.
    3. Use the filter flag in the Company predicate.

    Code changes (step 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];
    

    And the new method (step 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 讨论(0)
提交回复
热议问题