2010-01-08 100 views
11

我有一個NSArrayController,companiesController綁定到頂級核心數據實體Companies使用NSPredicate與核心數據建立深層關係

Company有許多Department「s和一個Department有許多Employee;這些由一對多關係departmentsemployees表示。

基於一個Employee我以爲我可以動態地用於過濾基於薪金UI所謂的方法中做到這一點的屬性salary

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

唉,這給我的錯誤:-[NSCFSet compare:]: unrecognized selector sent to instance

回答

17

在這種情況下不允許使用多對多密鑰。

相反,你可以做到以下幾點:

  1. 通過添加一個「過濾器」標記(布爾)屬性Department實體修改數據模型。
  2. 創建一個方法:獲取所有Department對象,將滿足條件的後半部分的部門的過濾器標誌設置爲YES,將其他部門的過濾器標誌設置爲NO,然後保存。
  3. 使用公司謂詞中的過濾器標誌。

代碼更改(步驟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]; 

而新的方法(步驟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

謝謝,這是有效的。似乎是一種解決方法,但這只是我猜想的核心數據的問題。 – raheel 2010-01-11 20:08:38

+0

我認爲它與Core Data如何將NSPredicate轉換爲SQLite語句有關。語法不明確:您是指某個部門中的任何或所有員工。另外,我是一名SQL新手,但我的猜測是,即使您的原始謂詞可以在簡單的SQL語句中完成,它也需要一個潛在的大連接,Apple可能會考慮對單個獲取進行過度記憶或性能密集型處理。 – gerry3 2010-01-11 22:12:08

+0

此外,我花了相當長的一段時間,所以一個贊成票將不勝感激:-)。 – gerry3 2010-01-11 22:13:21

10

你也可以做到這一點使用子查詢。

獲取所有部門。在「的」關係是公司對多個部門的倒數:

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

或者,如果你有更多的公司,只是想有一個員工提供工資的企業一定量「高於」。基於子查詢結果的子查詢

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

這是否適用於Mac OS和iOS的SQLite存儲?從Apple文檔(從iOS 5.0庫:核心數據編程指南「持久存儲特性」獲取謂詞和排序描述符 - 對於Mac OS可能會有所不同): 「對於您可以使用的謂詞還有其他限制SQLite存儲: 您無法將「任意」SQL查詢轉換爲謂詞。「 – Dalmazio 2011-11-08 09:47:34

+0

不知道,試試看:) – andershqst 2011-12-25 15:20:33

+0

最好的現實世界謂詞子查詢例子我遇到過 – 2012-05-02 10:34:26