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
"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.