Morgan Wilde
Morgan Wilde

Reputation: 17323

CoreData taking some time before NSFetchRequest finds new objects

I have a form in my app that allows users to input text and save it to CoreData in a UIManagedDocument.

While the app is running, I'm using an NSManagedObjectContext as the one and only context for inserting and fetching objects from this document.

The problem I have is - before saving I check for duplicates, and if I do subsequent inserts with waiting like 10 seconds, the context doesn't acknowledge already inserted ([matches count] returns 0) objects, and allows for duplicates.

If on the other hand I wait for some it - the result is as expected ([matches count] returns whatever number is true).

Code in full

@implementation Student (Create)

+ (Student *)withInfo:(NSDictionary *)infoDictionary inManagedContext:(NSManagedObjectContext *)context
{
    Student *student = nil;

    // Check for duplicates
    NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Student"];
    request.predicate = [NSPredicate predicateWithFormat:@"studentID == %@", (NSString *)infoDictionary[@"studentID"]];
    [request includesPendingChanges];

    NSError *error = nil;
    NSArray *matches = [context executeFetchRequest:request error:&error];

    if (!matches || ([matches count] > 1)) {
        // handle error
        NSLog(@"Error happens");
        for (Student *student in matches) {
            [context deleteObject:student];
            NSLog(@"studentID: %@", student.studentID);
        }
    } else if (![matches count]) {
        student = [NSEntityDescription insertNewObjectForEntityForName:@"Student" inManagedObjectContext:context];

        NSString *studentID = (NSString *)infoDictionary[@"studentID"];
        int studentIDint = [studentID intValue];
        NSLog(@"studentID: %d", studentIDint);

        student.studentID = [NSNumber numberWithInt:studentIDint];
        student.nameFirst = infoDictionary[@"nameFirst"];
        student.nameLast  = infoDictionary[@"nameLast"];

        // Add this students portrait as a relationship
        Portrait *portrait = [Portrait portraitWithAssetURL:infoDictionary[@"PortraitAssetURL"] inManagedObjectContext:context];
        student.portrait = portrait;

        NSError *errorSave;
        [context save:&errorSave];
        NSLog(@"errorSave: %@", errorSave);

        NSLog(@"creating a new student, matches count: %lu", (unsigned long)[matches count]);
    } else {
        student = [matches lastObject];
        NSLog(@"fetching old one, count: %lu", (unsigned long)[matches count]);
    }

    return student;
}

@end

Upvotes: 0

Views: 245

Answers (3)

AntonijoDev
AntonijoDev

Reputation: 1315

The code should look something like this:

NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"EntityName"];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"uniqueID == %@", newID]
[request setPredicate:predicate];
NSError *error = nil; 
NSArray *matches = [context executeFetchRequest:request error:&error];

if([matches count]){
    // update record
    SomeEnt *ent = [matches objectAtIndex:0];
    // ent set properties  
} 
else{
        // add new record
    SomeEnt *ent =  [NSEntityDescription insertNewObjectForEntityForName:@"EntityName" inManagedObjectContext:context];
    // ent set properties 
    // ...
}
NSError *error;
[context save:&error];

Upvotes: 1

Mundi
Mundi

Reputation: 80271

Something in your query does not make sense. You are sorting by uniqueID but only fetching one ID, so what is the sort for? Eliminate it.

Also, it does not make sense to check for uniqueID before saving. You should instead do this check before creating the new object.

This query should be very fast and not interfere with your insert at all. Consider also setting the fetchLimit to 1, but this is not really necessary.

NSArray *results = [self.managedObjectContext 
                   executeFetchRequest:request error:nil]; 

EntityName *object;
if (results.count) {
   object = results.lastObject;
}
else {
   object = [NSEntityDescription insertNewObject… ];
}

Upvotes: 0

slecorne
slecorne

Reputation: 1718

I think you should call [context save:&error] to save your modification to the store. Or add [request includesPendingChanges:YES] to allow request on pending unsaved changes.

Upvotes: 0

Related Questions