开发者

Core Data: Get Objects with the highest value in each category

I am currently struggling with my implementation of core data to get a "best of each category" effect - I have already tried to figure out a solution quite a long time now and I just don't get find the right approach <.<

I have three subclasses of NSManagedObjects, let's call them "Person", "Child" and "School" for explanatory reasons. Each Person can have multiple children, so there's a to-many relationship between those entities: Person <--->> Child

A Child attends a School, one school has many children, so we have: Child <<---> School

With this data structure, I want to get a list of children structured with these conditions:

  1. the children in the list must match certain requirements (e.g. age, attends certain school, ...) (easily accomplished with a NSPredicate)
  2. the list is sorted by the children's grades (or whatever you like, just an attribute)
  3. only the best graded child of each parent that match the requirements (in 1.) is taken into account !

I tried a lot and couldn't figure out a way to go ... the difficult part is to filter the parent's list of children to just get those which are the best graded of each individual parent, what has to be done after applying the requirements of (1.)

It would be optimal to wrap it into a NSFetchedResultsController so that the list can easily be displayed by a UITableView.

But what is the best approach? Can this be done with a matching predicate? I really appreciate your help!

:)

EDIT: The problem was solved with the following solution (which is not quite optimal when it's about performance but it does its job =) I replaced the entity names with the ones used in the explanation above. )

In Person.m:

- (NSArray *)bestChildrenWithPredicate:(NSPredicate *)aPredicate {    // create request

NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:[NSEntityDescription entityForName:@"Child" inManagedObjectContext:moc]];
// set predicate to fetch only children of current person and those that fit in the given predicate (possible to get back children of multiple schools)
NSPredicate *thePredicate = [NSPredicate predicateWithFormat:@"parent == %@",self];
if (aPredicate) thePredicate = [NSCompoundPredicate andPredicateWithSubpredicates:[NSArray arrayWithObjects:thePredicate, aPredicate, nil]];
[request setPredicate:thePredicate];
// sort results for grade and execute request
[request setSortDescriptors:[NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:@"grade开发者_如何转开发" ascending:YES]]];
NSError *error = nil;
NSArray *sortedResultsForPredicate = [moc executeFetchRequest:request error:&error];
[request release];
if (!sortedResultsForPredicate) {
    // handle error
    abort();
}
// create dictionary with schools as keys
NSMutableDictionary *bestResults = [[[NSMutableDictionary alloc] init] autorelease];
// loop through all results
for (Child *aResult in sortedResultsForPredicate) {
    // get string for dictionary index
    NSString *theSchoolKey = aResult.school.key;
    // check if the school already exists in the dictionary
    if (![bestResults objectForKey:theSchoolKey]) {
        [bestResults setObject:aResult forKey:theSchoolKey];
    } else {
        // get the current result
        Result *preResult = [bestResults objectForKey:theSchoolKey;
        // compare the results by grade and replace if new one is better
        NSComparisonResult comp = [preResult compareByGrade:aResult];
        if (comp==NSOrderedDescending||(comp==NSOrderedSame&&[[aResult valueForKey:@"date] compare:[preResult valueForKey:@"date"]]==NSOrderedAscending)) {
            [bestResults setObject:aResult forKey:theSchoolKey];
        }
    }
}
// return best graded children of each school sorted by date
return [[bestResults allValues] sortedArrayUsingSelector:@selector(compareByDate:)];

}


If you keep your parents in a separate entity, and have a relationship in the child entity, then you should be able to iterate through the parent list, pull only children for that parent, read the results into a sorted array, and pop the last value using [myArray lastResult]; You would then add this object to a mutable array that you could access in your application. I don't have time to put it into code yet, but the basics would be:

Fetch the parents entity into an array
Iterate the parents array, using the parent as the constraint for the child entity, and        use NSSortDescriptor initWithKey:@"grade" (or whatever you call it) ascending:YES. 
Read the results into a resultsArray
id bestKid = [resultsArray lastObject];
[myNSMutableArray addObject:bestKid];

Do that for each parent object, and then myNSMutableArray will contain an array of the best kid records.

Now, I'm more familiar with direct SQL than Core Data, so I welcome correction if this solution is not feasible! :)

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜