使用NSPredicate与核心数据建立深层关系

rah*_*eel 11 core-data objective-c nspredicate cocoa-design-patterns

我有一个NSArrayController,companiesController绑定到顶级Core Data实体,Companies.

A Company有很多Department,Department有很多Employee; 这些由1对多关系表示,departmentsemployees.

基于我认为的属性salary,Employee我可以动态地根据UI调用的方法中的工资进行过滤:

NSPredicate *predicate = [NSPredicate predicateWithFormat:@"ANY departments.employees.salary < %@", [NSNumber numberWithInt:23000]];
[companiesController setFilterPredicate:predicate];
Run Code Online (Sandbox Code Playgroud)

唉,这给了我错误:-[NSCFSet compare:]: unrecognized selector sent to instance.

ger*_*ry3 17

在这种情况下,不允许多对多密钥.

相反,您可以执行以下操作:

  1. 通过向Department实体添加"filter"标志(布尔)属性来修改数据模型.
  2. 创建一个方法:获取所有Department对象,为满足谓词后半部分条件的部门将filter标志设置为YES,为其他部门设置filter标志为NO,然后保存.
  3. 使用Company谓词中的过滤器标志.

代码更改(第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];
Run Code Online (Sandbox Code Playgroud)

而新方法(第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();
    } 
}
Run Code Online (Sandbox Code Playgroud)


and*_*qst 10

您也可以使用子查询来执行此操作.

获得所有部门.'of'关系是公司对许多部门的反面:

-(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];
}
Run Code Online (Sandbox Code Playgroud)

或者,如果你有更多的公司,只是希望雇员的薪水高于'一定数额的公司.基于子查询结果的子查询

-(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];
}
Run Code Online (Sandbox Code Playgroud)