NSFetchRequest 检索每个学生在 CoreData 实体中每个科目的最高考试分数

NSFetchRequest to retrieve Every Student's Maximum Test Score for Every Subject in CoreData Entity

我有一个 CoreData 实体,在不同长度的比赛中有多个性能记录。我想在 each 比赛中获得 each 运动员的最佳表现,然后将结果放入 CoreData Table 视图中。

这是我为完成此任务而想出的技巧。但是,这会影响我将结果放入 Table 视图中,其中比赛距离为 headers 部分:

- (void)setupFetchedResultsController // attaches an NSFetchRequest to this UITableViewController
{
MarksFromMeets* results = nil;

NSMutableArray * bestMarks = [[NSMutableArray alloc] init];


NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"MarksFromMeets"];

//    NSLog(@"self.athlete.athleteID = %@",self.athlete.athleteID);

request.predicate = [NSPredicate predicateWithFormat:@"(ANY whoRan.athleteID in %@) AND (eventPR > 0)",
                     self.athleteIDsForPredicate];
/* Call the records for selected athletes (PLURAL) */


request.sortDescriptors = [NSArray arrayWithObjects:
                           [NSSortDescriptor sortDescriptorWithKey:@"whoRan.athleteID" ascending:NO],
                           [NSSortDescriptor sortDescriptorWithKey:@"event" ascending:YES],
                           [NSSortDescriptor sortDescriptorWithKey:@"sortMark" ascending:YES],
                           nil];

以下块中的代码是我为每个运动员提取最佳表现的地方。

NSArray * allMarks = [self.headToHeadManagedObjectContext executeFetchRequest:request error:nil];

MarksFromMeets* tempMark;

for (MarksFromMeets* athletePRs in allMarks) {

    if (tempMark == nil) {
        tempMark = athletePRs;
    } else {
        if ([athletePRs.whoRan.athleteID isEqualToString:tempMark.whoRan.athleteID]) {
            if ([athletePRs.event isEqualToString:tempMark.event]) {
                if (athletePRs.sortMark < tempMark.sortMark) {
                    tempMark = athletePRs;
                }
            } else {
                [bestMarks addObject:tempMark];
                tempMark = athletePRs;
            }
        } else {
            [bestMarks addObject:tempMark];
            tempMark = athletePRs;
        }
    }
}
if (debug == 1) NSLog(@"bestMarks count: %lu \nallMarks count: %lu", (unsigned long)[bestMarks count], [allMarks count]);

[self setResultsArray:bestMarks];

NSArray bestMarks 有 27 个 NSManagedObjects,而提取请求返回 35 个。

下面的代码是我过去和仍然喜欢填充我的 CoreData TableView 的方式。

self.fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:request
                                                                    managedObjectContext:self.headToHeadManagedObjectContext
                                                                      sectionNameKeyPath:@"event"
                                                                            cacheName:nil];

NSError* error = nil;

results = [[self.headToHeadManagedObjectContext executeFetchRequest: request error:&error]objectAtIndex:0];

NSError* requestError = nil;
NSUInteger myCount = [self.headToHeadManagedObjectContext countForFetchRequest:request error:&requestError];
NSLog(@"In %@ and count of results = %lu", NSStringFromClass([self class]),(unsigned long)myCount);
if (!myCount || myCount == 0) {
    NSMutableString* titleText = [NSMutableString stringWithFormat:@"No Records Found"];
    NSMutableString* messageText = [NSMutableString stringWithFormat:@"There were no records found for the %lu athletes selected. Contact ITrackPerfomance using this list of Athlete ID's: %@",  (unsigned long)[self.athleteIDsForPredicate count], self.athleteIDsForPredicate];

    NSString* cancelText = @"Okay";

    [self displayAlertBoxWithTitle:(NSString*)titleText message:(NSString*) messageText cancelButton:(NSString*) cancelText];
}
}

有没有办法用 NSFetchRequest 谓词来做到这一点?

或者我可以通过将 Managed Objects 放入 NSDictionaries 的 NSArray 中来创建部分,其中每个 NSDictionary 是不同的比赛距离吗?

感谢您的帮助。如果我完全偏离了正确的道路并且有更有效的方法来实现这一点,我也很高兴知道!

好的,这就是我的想法。希望这可以帮助其他人: 我根据 "class"(在我的例子中是种族)将托管对象解析为 NSMutableArrays。然后我将每个 NSM 数组放入一个 NSMutableDictionary 中,其中索引作为键。该字典及其中的数组随后成为确定节数和节中行数的基础。

- (void)setupFetchedResultsController // attaches an NSFetchRequest to this UITableViewController
{
MarksFromMeets* results = nil;

NSMutableArray * bestMarks = [[NSMutableArray alloc] init];
NSMutableDictionary * dictionaryOfMarksByRace = [[NSMutableDictionary alloc] init];

NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"MarksFromMeets"];

//    NSLog(@"self.athlete.athleteID = %@",self.athlete.athleteID);

request.predicate = [NSPredicate predicateWithFormat:@"(ANY whoRan.athleteID in %@) AND (eventPR > 0)",
                     self.athleteIDsForPredicate];
/* Call the records for selected athletes (PLURAL) */


request.sortDescriptors = [NSArray arrayWithObjects:
                           [NSSortDescriptor sortDescriptorWithKey:@"event" ascending:YES],
                           [NSSortDescriptor sortDescriptorWithKey:@"whoRan.athleteID" ascending:NO],
                           [NSSortDescriptor sortDescriptorWithKey:@"sortMark" ascending:YES],
                           nil];


NSArray * allMarks = [self.headToHeadManagedObjectContext executeFetchRequest:request error:nil];

MarksFromMeets* previousMark;

int i = 0;
int j = 0;
for (MarksFromMeets* athletePRs in allMarks) {
    NSArray* sortedMarks;
    if (previousMark == nil) {
        previousMark = athletePRs;
    } else {
        if ([athletePRs.event isEqualToString:previousMark.event]) {
            if ([athletePRs.whoRan.athleteID isEqualToString:previousMark.whoRan.athleteID]) {
                NSLog(@"athletePRs.%@ = previousMark.%@",athletePRs.sortMark,previousMark.sortMark);


                if ([athletePRs.sortMark intValue] < [previousMark.sortMark intValue]) {
                    previousMark = athletePRs;
                    NSLog(@"Should NEVER happen");
                }
            } else {
                [bestMarks addObject:previousMark];
                NSLog(@"Adding %@, %@, %@ to bestMarks for i = %d",previousMark.event, previousMark.markInEvent, previousMark.whoRan.athleteFullName,i);
                previousMark = athletePRs;
                NSLog(@"tempMark record now %@",previousMark.whoRan.athleteFullName);
                if (j == [allMarks count]-1) {
                    [bestMarks addObject:previousMark]; //Now tempMark is last MarksForMeet object
                    sortedMarks = [self sortNSMutableArray:bestMarks];
                    [dictionaryOfMarksByRace setObject:sortedMarks forKey:[NSNumber numberWithInt:i]];
                    bestMarks = [[NSMutableArray alloc] init];

                }
            }
        } else {
            [bestMarks addObject:previousMark];
            previousMark = athletePRs;
            sortedMarks = [self sortNSMutableArray:bestMarks];
            [dictionaryOfMarksByRace setObject:sortedMarks forKey:[NSNumber numberWithInt:i]];
            NSLog(@"Adding %@ to bestMarks for i = %d",previousMark.event,i);
            bestMarks = [[NSMutableArray alloc] init];
            // reallocate bestMarks to ensure values in NSMutableDictionary are unique
            i++;
            if (j == [allMarks count]-1) {
                [bestMarks addObject:previousMark];
                sortedMarks = [self sortNSMutableArray:bestMarks];
                [dictionaryOfMarksByRace setObject:sortedMarks forKey:[NSNumber numberWithInt:i]];
                bestMarks = [[NSMutableArray alloc] init];
                // reallocate bestMarks to ensure values in NSMutableDictionary are unique
            }
        }
    }
    j++;
}


[self setResultsDictionary:dictionaryOfMarksByRace];

}

过滤数据后不得不做一个度假村。可能有更有效的方法来执行此操作,但这种蛮力方法有效,因为我在这种方法中从 Core Data 中提取的记录相对较少。