2010-01-08 31 views
11

Tôi có một NSArrayController, companiesController được liên kết với một thực thể Dữ liệu chính cấp cao nhất, Companies.Sử dụng NSPredicate với Dữ liệu cốt lõi cho các mối quan hệ sâu

A Company có nhiều Department và một số Department có nhiều Employee; chúng được đại diện bởi các mối quan hệ 1 đến nhiều, departmentsemployees.

Dựa trên các thuộc tính của một salaryEmployee tôi nghĩ rằng tôi tự động có thể làm điều này cho lọc dựa trên mức lương bên trong một phương pháp giao diện người dùng được gọi là:

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

Alas, điều này mang lại cho tôi những lỗi: -[NSCFSet compare:]: unrecognized selector sent to instance.

Trả lời

17

Không được phép sử dụng nhiều khóa nhiều lần trong trường hợp này.

Thay vào đó, bạn có thể làm như sau:

  1. Sửa đổi các mô hình dữ liệu bằng cách thêm một "bộ lọc" cờ (Boolean) thuộc tính đến tổ chức Cục.
  2. Tạo phương thức để: tìm nạp tất cả các đối tượng của Bộ, đặt cờ lọc thành CÓ cho các phòng đáp ứng tiêu chí của nửa sau của biến vị ngữ, đặt cờ bộ lọc thành NO cho các phòng ban khác và lưu.
  3. Sử dụng cờ bộ lọc trong vị từ Công ty.

thay đổi Mã (bước 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]; 

Và phương pháp mới (bước 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

Cảm ơn, công trình này. Có vẻ như một giải pháp thay thế, nhưng đó chỉ là những vấn đề của Core Data mà tôi đoán. – raheel

+0

Tôi cho rằng nó có liên quan đến cách dữ liệu lõi dịch NSPredicate thành (các) câu lệnh SQLite. Cú pháp là mơ hồ: bạn có nghĩa là BẤT CỨ hoặc TẤT CẢ Nhân viên (s) trong một Sở cụ thể. Ngoài ra, tôi là một người mới làm quen với SQL, nhưng tôi đoán là ngay cả khi biến vị ngữ ban đầu của bạn có thể được thực hiện trong một câu lệnh SQL đơn giản, nó sẽ đòi hỏi một sự tham gia lớn mà Apple có thể xem xét quá bộ nhớ hoặc hiệu suất chuyên sâu cho một lần tìm nạp đơn lẻ. – gerry3

+0

Ngoài ra, tôi đã dành khá nhiều thời gian cho việc này để bỏ phiếu sẽ được đánh giá cao :-). – gerry3

10

Bạn cũng có thể làm điều này bằng truy vấn con.

Nhận tất cả các phòng ban. Mối quan hệ 'của' là nghịch đảo của các phòng ban của nhiều công ty:

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

Hoặc, nếu bạn có nhiều công ty hơn và chỉ muốn các công ty có nhân viên có lương cao hơn 'một số tiền. Truy vấn con dựa trên kết quả của truy vấn phụ

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

Tính năng này có hoạt động với một cửa hàng SQLite cho cả Mac OS và iOS không? Từ tài liệu của Apple (từ thư viện iOS 5.0: Hướng dẫn lập trình dữ liệu cốt lõi> Tính năng lưu trữ lâu dài> Tìm nạp số mũ và bộ mô tả sắp xếp - có thể khác với Mac OS): "Có những hạn chế bổ sung đối với các biến vị ngữ bạn có thể sử dụng Cửa hàng SQLite: Bạn không nhất thiết có thể dịch các truy vấn SQL "tùy ý" thành các vị từ." – Dalmazio

+0

Không biết. Hãy thử nó ra :) – andershqst

+0

Ví dụ thế giới thực tốt nhất Ví dụ về SubQuery Tôi đã gặp phải –

Các vấn đề liên quan