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 exists, I'd rather return it than create a new object.
I have a simple App which has a table view with a plus button in the Navigation Bar; the user clicks that and is presented with a View Controller with 4 text fields. They fill in that information, press save and it gets saved to Core Data and displayed in the TableView (through the use of NSFetchedResultsControllers).
The data model is as follows:
Transaction Entity with isReceived BOOL attribute
Person Entity with name string attribute
Occasion Entity with title string attribute
Item Entity with amount string attribute
The transaction has a relationship to the Person (whoBy), Occasion (Occasion) and Item entities.
In the view controller with the save method, I have the code below which will insert new objects into the Transaction, Person, Occasion Entities, etc. Each Transaction is of course unique, but with each transaction, the user can select an existing PERSON and/or Occasion and if that person then does not exist, it will be created (likewise with the occasion).
I'm slightly confused as to the format of the code here.
EDIT: I have tried a combination of code and can just not get this working. In the code below, I'm referencing person.name in the predicate, but I also tried creation a local NSString variable to hold the self.nameTextField.text
code but that did nothing. I tried creating a NSString property to reference it that way and that not work. I tried using the words MATCHES, LIKE, CONTAINS, ==
and every combination in-between.
- (IBAction)save:(id)sender
{
NSManagedObjectContext *context = [self managedObjectContext];
Transaction *transaction= [NSEntityDescription insertNewObjectForEntityForName:@"Transaction" inManagedObjectContext:context];
Person *person = [NSEntityDescription insertNewObjectForEntityForName:@"Person" inManagedObjectContext:context];
Occasion *occasion = [NSEntityDescription insertNewObjectForEntityForName:@"Occasion" inManagedObjectContext:context];
Item *amount = [NSEntityDescription insertNewObjectForEntityForName:@"item" inManagedObjectContext:context];
NSFetchRequest *personFind = [NSFetchRequest fetchRequestWithEntityName:@"Person"];
personFind.predicate = [NSPredicate predicateWithFormat:@"name == %@", person.name];
// I have tried every combination of the predicate like MATCHES, LIKE.
// I created a local NSString variable and an NSString property
NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"name" ascending:YES];
personFind.sortDescriptors = [NSArray arrayWithObject:sortDescriptor];
NSError *error = nil;
NSArray *matches = [context executeFetchRequest:personFind error:&error];
if (!matches || ([matches count] > 1))
{
// Handle Error
}
else if ([matches count] == 0)
{
person.name = self.nameTextField.text;
transaction.whoBy = person;
occasion.title = self.occasionTextField.text;
transaction.occasion = occasion;
}
else
{
person = [matches lastObject];
transaction.whoBy = person;
occasion.title = self.occasionTextField.text
transaction.occasion = occasion;
}
if (![context save:&error])
{
NSLog(@"Can't save! %@ %@", error, [error localizedDescription]);
}
[self dismissViewControllerAnimated:YES completion:nil];
}
Logically, what I want to achieve is:
When the user is adding a Transaction, check if it's for a new person or an existing one — if it's an existing one, choose it from a list of Persons (and when the user selects a person, get its NSManagedObjectID). If it's a new one, create it on the spot.
The same for the Occasion.
Set all the other fields of the Transaction object (amount, etc.).
My question is:
- What predicate do I use to get this working?
When I put a break point in this method, a NEW NAME (one that doesn't exist before) correctly calls the else if ([matches count] == 0)
method and if I create an entry with an existing name, it calls the
else
{
person = [matches lastObject];
transaction.whoBy = person;
occasion.title = self.occasionTextField.text
transaction.occasion = occasion;
}
Even with the this statement, it is still creating a new person object for the same name.
I will correctly implement the occasion after getting the person working, but I'm just lost on how to get this working.
Any help would be massively appreciated!
See Question&Answers more detail:
os