Querying Core Data for Specific Attributes when Creating New Objects and returning the object if it exists, or creating a new one if it does not

后端 未结 1 632
野趣味
野趣味 2020-12-17 06:20

I have a problem checking whether a particular attribute of an Entity exists in the Core Data Database (through predicates) before creating a new object; if the object exist

相关标签:
1条回答
  • 2020-12-17 06:33

    "Is this correct?":
    No. You are creating a new Person and Occasion objects whether you are using an existing person/occasion or not.
    First check for existence and only if the object not already exist, insert a new one.
    Alternatively, if the person/occasion exist, delete the inserted object.

    "How do I retrieve the managedObjectID for person/event?":

    Person* person = /*Get an existing person object*/
    NSManagedObjectID* personId = person.objectID /*This is the person object ID, will work for any NSManagedObject subclass*/
    

    To find a person that start with a string str use this predicate in a fetch request:

    /*UNTESTED*/
    [NSPredicate predicateWithFormat:@"(name BEGINSWITH[cd] %@)", str];
    

    Edit:

    To be more precise, you practice find or create using something like this:
    (this is very limited, and only good for a single object performance-wise) (NOT TESTED)

    - (NSManagedObject*) findOrCreateObjectByValue:(id)value
                                      propertyName:(NSString*)propertyName
                                        entityName:(NSString*)entityName
                                    additionalInfo:(NSDictionary*)additionalInfo
                                           context:(NSManagedObjectContext*)context
                                             error:(NSError* __autoreleasing*)error
    {
        NSManagedObject* res = nil;
    
        NSFetchRequest* r = [NSFetchRequest fetchRequestWithEntityName:entityName];
        [r setPredicate:[NSPredicate predicateWithFormat:@"%K == %@",propertyName,value]];
    
        NSArray* matched = [context executeFetchRequest:r
                                                  error:error];
    
        if (matched) {
            if ([matched count] < 2) {
                res = [matched lastObject];
                if (!res) { //No existing objects found, create one
                    res = [NSEntityDescription insertNewObjectForEntityForName:entityName
                                                        inManagedObjectContext:context];
                    [res setValue:value
                           forKey:propertyName];
                    [res setValuesForKeysWithDictionary:additionalInfo];
                }
            } else {
                if (error) {
                    *error = [NSError errorWithDomain:@"some_domain"
                                                 code:9999
                                             userInfo:@{@"description" : @"duplicates found"}];
                }
            }
        }
    
        return res;
    }
    

    So now, your save: method should look something like:
    (I assume here that the person name and occasion title are held by a UITextField on the view controller [txtPersonName and txtOccasionTitle respectively] )

    - (void) save:(id)sender
    {
        //create a clean context so that changes could be discarded automatically on failure
        NSManagedObjectContext* context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
        [context setParentContext:[self managedObjectContext]];
    
        //A Transaction is always created in save event, so add it to the context
        Transaction* transaction = [NSEntityDescription insertNewObjectForEntityForName:@"Transaction" inManagedObjectContext:context];
    
        __block NSError* error = nil;
    
        Person* p = (Person*)[self findOrCreateObjectByValue:self.txtPersonName.text
                                                propertyName:@"name"
                                                  entityName:@"Person"
                                              additionalInfo:nil
                                                     context:context
                                                       error:&error];
        if (!p) {
            NSLog(@"Error: %@, person name: %@",error,self.txtPersonName.text);
            return;
        }
    
        Occasion* o = (Occasion*)[self findOrCreateObjectByValue:self.txtOccasionTitle.text
                                                    propertyName:@"title"
                                                      entityName:@"Occasion"
                                                  additionalInfo:nil
                                                         context:context
                                                           error:&error];
        if (!o) {
            NSLog(@"Error: %@, occasion title: %@",error,self.txtOccasionTitle.text);
            return;
        }
    
        transaction.whoBy = p;
        transaction.occasion = o;
        //Not sure what you are using this property for
        transaction.item = [NSEntityDescription insertNewObjectForEntityForName:@"Item"
                                                         inManagedObjectContext:context];
    
        NSManagedObjectContext* ctx = context;
        if ([context obtainPermanentIDsForObjects:[context.insertedObjects allObjects]
                                            error:&error])
        {
            //save your changes to the store
            __block BOOL saveSuccess = YES;
            while (ctx && saveSuccess) {
                [ctx performBlockAndWait:^{
                    saveSuccess = [ctx save:&error];
                }];
                ctx = [ctx parentContext];
            }
    
            if (!saveSuccess) {
                NSLog(@"Could not save transaction, error: %@",error);
            }
        } else {
            NSLog(@"Could not obtain IDs for inserted objects, error: %@",error);
        }
    
        //Do what you have to do next
    }
    

    This is just for making things a bit clearer on what you should do to avoid duplications, and reuse existing objects.

    0 讨论(0)
提交回复
热议问题