2012-02-06 18 views
7

Hiện đang sử dụng Dữ liệu chính. Tôi có một bảng trong đó tôi đang cố gắng để lấy thông tin cùng những dòng này:Đếm riêng biệt qua Dữ liệu chính, NSExpression vào NSFetchedResultsController

SELECT item, COUNT(*) FROM myTable GROUP BY item; 

để sản xuất loại này kết quả:

+---------+------+-------+ 
| item  | COUNT(*) | 
+---------+------+-------+ 
| group 1  | 2  | 
| group 2  | 5  | 
| group 3  | 8  | 
+---------+------+-------+ 

tôi đã có ý tưởng sáng để sử dụng một NSExpression , với hy vọng có Dữ liệu chính thực hiện tất cả công việc cho tôi. Tôi bắt đầu quay bánh xe của tôi. Chức năng biểu hiện : bị treo trên tôi. Ngoại lệ không phải là rất rõ ràng. Việc sử dụng các hàm biểu thức khác, chẳng hạn như tổng: không làm hỏng ứng dụng.

Sẽ thật tuyệt nếu lưu trữ kết quả theo số NSFetchedResultsController. Tôi đã khám phá các tùy chọn khác, không có tùy chọn nào trong số đó không quá hấp dẫn. Nó sẽ có ý nghĩa hơn để viết một truy vấn SQL và làm cho nó hơn với, hơn là sử dụng dữ liệu lõi như một wrapper SQL trong trường hợp này?

Đối với mã nguồn tham chiếu của bạn bên dưới.

NSExpression *keyPathExpression = [NSExpression expressionForKeyPath:@"item"]; 
NSExpression *totalExpression = [NSExpression expressionForFunction:@"count:" arguments:[NSArray arrayWithObject:keyPathExpression]]; 

NSExpressionDescription * totalExpressionDescription = [[NSExpressionDescription alloc] init]; 
[totalExpressionDescription setExpression:totalExpression]; 
[totalExpressionDescription setExpressionResultType:NSInteger64AttributeType]; 
[totalExpressionDescription setName:@"totalInstances"]; 

NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init]; 
NSEntityDescription *entity = [NSEntityDescription entityForName:@"myEntity" inManagedObjectContext:self.managedObjectContext]; 
NSArray *propertiesToFetch = [[NSArray alloc] initWithObjects:strFieldName, totalExpressionDescription, nil]; 

[fetchRequest setEntity:entity]; 
[fetchRequest setReturnsDistinctResults:YES]; 
[fetchRequest setResultType:NSDictionaryResultType]; 
[fetchRequest setPropertiesToFetch:propertiesToFetch]; 
[fetchRequest setFetchBatchSize:20]; 

NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:strFieldName ascending:YES]; 
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil]; 
[fetchRequest setSortDescriptors:sortDescriptors]; 

NSFetchedResultsController* aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:[self managedObjectContext] sectionNameKeyPath:nil cacheName:nil]; 

... 

NSError *error = nil; 
if (![self.fetchedResultsController performFetch:&error]) 
{ 
    NSLog(@"Unresolved error %@, %@", error, [error userInfo]); 
    abort(); 
} 

Trả lời

14

này có thể với NSExpression như bạn đề xuất ban đầu, trong ví dụ giả tạo của tôi, tôi đã là một thực thể gọi là "Người" với một tài sản gọi là "EmailAddress" mà tôi muốn để có được đếm cho.

NSPropertyDescription *propDesc = [[[[model entitiesByName] objectForKey:@"Person"] propertiesByName] objectForKey:@"emailAddress"]; 
NSExpression *emailExpr = [NSExpression expressionForKeyPath:@"emailAddress"]; 
NSExpression *countExpr = [NSExpression expressionForFunction:@"count:" arguments:[NSArray arrayWithObject:emailExpr]]; 
NSExpressionDescription *exprDesc = [[NSExpressionDescription alloc] init]; 
[exprDesc setExpression:countExpr]; 
[exprDesc setExpressionResultType:NSInteger64AttributeType]; 
[exprDesc setName:@"count"]; 

NSFetchRequest *fr = [NSFetchRequest fetchRequestWithEntityName:@"Person"]; 
[fr setPropertiesToGroupBy:[NSArray arrayWithObject:propDesc]]; 
[fr setPropertiesToFetch:[NSArray arrayWithObjects:propDesc, exprDesc, nil]]; 
[fr setResultType:NSDictionaryResultType]; 
NSArray *results = [moc executeFetchRequest:fr error:&error]; 

Tôi đã viết một đoạn mã để điền trước các cơ sở dữ liệu với 1.000 hồ sơ:

NSArray *emailAddresses = [NSArray arrayWithObjects:@"[email protected]", @"[email protected]", @"[email protected]", @"[email protected]", @"[email protected]", nil]; 
    for (int i = 0; i < 1000; i++) { 
     NSManagedObject *person = [NSEntityDescription insertNewObjectForEntityForName:@"Person" inManagedObjectContext:moc]; 
     [person setValue:[NSNumber numberWithInt:i] forKey:@"aNumber"]; 
     [person setValue:[[NSUUID UUID] UUIDString] forKey:@"aUUID"]; 
     [person setValue:[emailAddresses objectAtIndex:(i % [emailAddresses count])] forKey:@"emailAddress"]; 
    } 

Đoạn mã trên sẽ chèn mỗi địa chỉ email 200 lần, đây là kết quả:

2012-05-31 15:17:42.160 Scratch[16084:10d03] CoreData: sql: SELECT t0.ZEMAILADDRESS, COUNT(t0.ZEMAILADDRESS) FROM ZPERSON t0 GROUP BY t0.ZEMAILADDRESS 
2012-05-31 15:17:42.162 Scratch[16084:10d03] CoreData: annotation: sql connection fetch time: 0.0024s 
2012-05-31 15:17:42.163 Scratch[16084:10d03] CoreData: annotation: total fetch execution time: 0.0029s for 5 rows. 
(gdb) po results 
(NSArray *) $2 = 0x0f811280 <_PFArray 0xf811280>(
{ 
    count = 200; 
    emailAddress = "[email protected]"; 
}, 
{ 
    count = 200; 
    emailAddress = "[email protected]"; 
}, 
{ 
    count = 200; 
    emailAddress = "[email protected]"; 
}, 
{ 
    count = 200; 
    emailAddress = "[email protected]"; 
}, 
{ 
    count = 200; 
    emailAddress = "[email protected]"; 
} 
) 
+1

Tôi thấy tôi đã thiếu NSPropertyDescription, điều này sẽ cho phép NSFetchRequest được hiểu chính xác dưới dạng truy vấn SQL bằng cách thêm dòng "Nhóm theo mục". Tôi không biết về đối tượng đó tại thời điểm đăng bài. Tôi có thể đã sử dụng câu trả lời của bạn vào tháng 2 ... lol. Điều này là tốt để biết, trong trường hợp tôi quyết định sử dụng giải pháp này trong tương lai. Câu trả lời của bạn được đánh giá cao. :-) –

+0

Một lưu ý, tác giả gốc đã đề cập đến việc sử dụng NSFetchedResultsController với nhóm. Thật không may cho 'setPropertiesToGroupBy' để làm việc bạn cần phải' setResultType: NSDictionaryResultType' mà vô hiệu hóa các thay đổi theo dõi. Xem http://stackoverflow.com/a/4361198/287403 –

+0

Có thể sắp xếp tất cả chúng bằng cách đếm không? – Andy