Core data - Building a NSPredicate from a ManyToMany relationship - core-data

This is a follow up question to my previous question on:
Core data: Managing employee contracts in a many-to-many relationship?
There is a diagram on that question, and as a quick reminder there is the following:
company --< contracts >-- employees
I have been able to manually save 1 entity inside each of the entities, and verified them all in NSLog.
I've created a CompanyListPage which lists all companies. The idea is that when you click on a company you will be presented with a list of all employees who have a contract with said company.
As context see below:
Company:
name: A
Contract:
length: 33 wks
salary: 20000
Employee:
name: Bob Jones
In my didSelectRowAtIndex page within my CompanyListPage I have the following.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
Company *c = [fetchedResultsController objectAtIndexPath:indexPath];
NSLog(#"You clicked %#", c.name);
NSString *companyName = c.name;
EmployeesListPage *employeesListPage = [[EmployeesListPage alloc] initWithNibName:#"EmployeesListPage" bundle:[NSBundle mainBundle]];
[self.navigationController pushViewController:employeesListPage animated:YES];
employeesListPage.title = companyName;
employeesListPage.managedObjectContext = self.context;
employeesListPage.managedObject = c;
[superstarsList release];
}
The problem however is, I am not sure what my NSPredicate should look like when I eventually go to the employeesListPage.
At the moment, its this:
- (NSFetchedResultsController *)fetchedResultsController
{
if (fetchedResultsController != nil) {
return fetchedResultsController;
}
// Create and configure a fetch request
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Employees" inManagedObjectContext:managedObjectContext];
[fetchRequest setEntity:entity];
// Create the sort descriptors array
NSSortDescriptor *authorDescriptor = [[NSSortDescriptor alloc] initWithKey:#"name" ascending:YES];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:authorDescriptor, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
// Create and initialize the fetch results controller
NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:managedObjectContext sectionNameKeyPath:nil cacheName:#"Root"];
self.fetchedResultsController = aFetchedResultsController;
fetchedResultsController.delegate = self;
// Memory management.
[aFetchedResultsController release];
[fetchRequest release];
[authorDescriptor release];
[sortDescriptors release];
return fetchedResultsController;
}
Obviously this is wrong, because its not:
a) Looking in the contracts entity
b) Using the company entity in any way, shape or form
I know I need to use a NSPredicate, but I just know how to make it say "Find me all the employees with a contract length > 0 and working with company A" then order it by the name of the person descending, or even order it by the least contract length first.
Any pointers or help on this would be great. Thank you.
EDIT: First attempt (removed because I got it to work following an answer provided below)
EDIT: Unable to get contract information back?
I've been able to get all the employees that work for Company A back in my table view controller.
However I'm wanting to display in my cell information about the employee and their contract length/salary.
I've tried the following:
Employee *emp = [fetchedResultsController objectAtIndexPath:indexPath];
NSString *firstname = emp.firstname;
NSString *surname = emp.surname;
NSString *fullname = [firstname stringByAppendingString:#" "];
fullname = [fullname stringByAppendingString:surname];
// Logging tests
NSLog(#"Name: %#", fullname); // This is fine
NSLog(#"Contracts: %#", emp.empContracts); // This tells me of a problem with "Relationship fault for <NSRelationshipDescription: 0x602fdd0>"
I believe I need to get the NSPredicate to grab all the contract data, and not just the contract data; however I may be mistaken.
Again, help on this would be greatly appreciated.

I think if you use the ANY keyword, you'll restore the left side of the equation to a single quantity, which will agree with the right side of the equation:
NSPredicate *predicate = [NSPredicate predicateWithFormat:#“ANY contracts.employer == %#“, employer];

I think I have an answer now.
I did the following in my table view and got a valid relationship and all the output; however I am not sure if I am doing it right because it involves a for-loop.
I used the following StackOverflow related question/answer for my solution.
- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath
{
Employee *emp = [fetchedResultsController objectAtIndexPath:indexPath];
NSString *firstname = emp.firstname;
NSString *surname = emp.surname;
NSString *fullname = [firstname stringByAppendingString:#" "];
fullname = [fullname stringByAppendingString:surname];
NSLog(#"Employee: %#", fullname);
// Output the contract deals.
for (Contracts *deals in emp.contracts)
{
NSNumber *cLength = deals.length;
NSNumber *cSalary = deals.salary;
NSLog(#"Length: %#", cLength);
NSLog(#"Salary: %#", cSalary);
} // next
}
The next step for me is to include this in a custom view with custom labels to hold all this info.
If the for-loop is not the most efficient way to do this, I would welcome any suggestions/improvements, or even what is considered best practice.
Thank you.

Looks like it’s coming along well. I think all you need from there is to set the cell’s text: cell.textLabel = fullname.
But I’m not clear why you’re delving back into the contracts relationship — until I look at your sample text at the top. There, it looks like what you want is a list of contracts for the employer, and for each contract you want to show its to-one employee relationship and other attrs. In which case you don’t need a new fetch at all; you already have the employer and, through its to-many contracts relationship, you also have the contracts entities and, through them, the term, salary, employee, whatever.
Upon selection change in the employers table, you would do something like this:
NSUInteger row = [indexPath row];
Employer *employer = [self.arrayOfEmployersUsedToPopulateTable objectAtIndex:row];
self.selectedEmployer = employer;
self.arrayOfSelectedEmployersContracts = [employer.contracts allObjects]; // which probably faults them, but I think that’s OK here
// Then make a call to reload the other table, the one presenting the contracts info.
In the contracts table, you’d refer back to the selected employer, and present info for each contract:
- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath {
NSUInteger row = [indexPath row];
Contract *contract = [self.arrayOfSelectedEmployersContracts objectAtIndex:row];
NSUInteger column = [indexPath column];
switch (column) {
(0) :
cell.textLabel = contract.length; // maybe you have to use an NSNumber method to convert to string, but probably not
break;
(1):
cell.textLabel = contract.employee.firstname;
break;
// and so forth
}}
P.S. For the UITableCell stuff, I consulted Beginning iPhone Development, by Mark and LaMarche, “Using the New Table View Cell.” You might like this book too.

Related

Saving Core Data related data and retrieving with NSPredicate and NSFetchedResultsController with multiple entities

I'm fairly new to Core Data and am still trying to understand accessing and filtering related data. My problem is either I'm not getting the data correctly into the managedObjectContext or I'm not pulling it out correctly. (I think the first, but I'm not sure.)
Here's my data model with two entities related one to many: (I plan to refactor once I get one level of relationship working.)
I have a SeasonsVC in which you click on a season name and the list of games for that season is supposed to appear in the GamesVC and you have the option to add or edit an existing game. This works fine at a first pass. I can add and edit games via this code in the GameDetailsVC:
-(IBAction)done:(UIBarButtonItem *)sender {
Game *game = nil;
if (self.gameToEdit != nil) {
game = self.gameToEdit;
NSLog(#"Hitting gametoedit");
} else {
game = [NSEntityDescription insertNewObjectForEntityForName:#"Game" inManagedObjectContext:self.managedObjectContext];
NSLog(#"Hitting new game");
}
game.opponent = self.opponentTextField.text;
//season.seasonDescription = self.seasonDescriptionTextView.text;
NSLog(#"Game to edit: %#", game.opponent);
//NSLog(#"Season: %#", season);
//NSLog(#"MOC in done: %#", self.managedObjectContext);
//NSLog(#"Season name: %#", season.seasonName);
[self dismissViewControllerAnimated:YES completion:nil];
}
I can then see the games in the GamesVC via the fetchedResultsController and delegate methods, but each game is associated with every season. Once I try to filter the data with a predicate so that I only see the games that were added for that season all the games disappear. Here's the code for that from the GamesVC:
- (NSFetchedResultsController *)fetchedResultsController {
if (_fetchedResultsController != nil) {
return _fetchedResultsController;
}
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription
entityForName:#"Game" inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];
NSLog(#"Season name for predicate %#", self.season.seasonName);//shows correct season name
NSPredicate *predicate = [NSPredicate predicateWithFormat:[NSString stringWithFormat:#"season.seasonName like '%#'", self.season.seasonName]];
[fetchRequest setPredicate: predicate];
NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:#"dateOfGame" ascending:NO] ;
[fetchRequest setSortDescriptors:#[sortDescriptor]];
[fetchRequest setFetchBatchSize:20];
NSFetchedResultsController *theFetchedResultsController =
[[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
managedObjectContext:self.managedObjectContext sectionNameKeyPath:nil
cacheName:#"Root2"];
self.fetchedResultsController = theFetchedResultsController;
self.fetchedResultsController.delegate = self;
return _fetchedResultsController;
}
Since I can log the correct season name right before the predicate statement, I think that the added games are not getting "associated" with the correct season when I put them in the MOC in the done: method shown above; otherwise, I'd expect the predicate to find them.
Can you help this rookie? Thanks.
A day later I have this sorted. I needed to make three changes to what I was doing.
First, in my prepareForSegue in my GameListVC I needed to pass the season along to the GameDetailsVC by changing the code to this. (Just added the one line: controller.season = self.season)
//pass the Season object to be edited
NSIndexPath *indexPath = [self.tableView indexPathForCell:sender];
Game *gameToEdit = [self.fetchedResultsController objectAtIndexPath:indexPath];
controller.gameToEdit = gameToEdit;
controller.season = self.season;
Second, I had to put the new/edited game object into the MOC by adding these two lines to my done: method in the GameDetailsVC.
NSMutableSet *games = [self.season mutableSetValueForKey:#"games"];
[games addObject:game];
Third, I needed to simplify my predicate statement in my fetchedResultsController method in the GameListVC.
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"season.seasonName like %#", self.season.seasonName];
So, to answer my own question, I was both not saving the game linked to the season and my predicate was wrong.
I hope some of this helps another rookie.

Fetch one-to-many relationship fault still shows after adding setRelationshipKeyPathsForPrefetching

Let's say my data model has two entities: Department and Person. Departments has a to-many relationship called 'departmentToPerson' with Person. Person has a to-one relationship called 'personToDepartment' with Department.
I want to populate an array of people belonging to a selected department. To selected the department I've created a UILabel that displays a departmentName that is selected from a popup tableview. When I run the app the log shows:
personToDepartment.departmentName == (entity:
Department; id: 0x8cc1920
;
data: {
departmentName = Marketing;
departmentToPerson = "";
I've read the purpose of faults and implemented setRelationshipKeyPathsForPrefetching, but still I get the fault. I'll put in the disclaimer that I'm a newbie and may be missing something obvious. When I delete the predicate my table view populates with all personName. Here's the code:
- (NSFetchedResultsController *)fetchedResultsController {
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription
entityForName:#"Person" inManagedObjectContext:_managedObjectContext];
[fetchRequest setEntity:entity];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"personToDepartment.departmentName = %#", selectedDepartment];
NSLog(#"predicate is: %#",predicate);
[fetchRequest setPredicate:predicate];
[fetchRequest setRelationshipKeyPathsForPrefetching:[NSArray arrayWithObjects: #"departmentToPerson", nil]];
fetchRequest.returnsObjectsAsFaults = NO;
NSSortDescriptor *sort = [[NSSortDescriptor alloc]
initWithKey:#"personName" ascending:YES];
[fetchRequest setSortDescriptors:[NSArray arrayWithObject:sort]];
[fetchRequest setFetchBatchSize:20];
NSFetchedResultsController *theFetchedResultsController =
[[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
managedObjectContext:_managedObjectContext sectionNameKeyPath:nil
cacheName:nil];
self.fetchedResultsController = theFetchedResultsController;
_fetchedResultsController.delegate = self;
return _fetchedResultsController;
}
Again, I select a new department from the UILabel, the log displays selectedDepartment, but then states relationship fault and does not populate the table.
Thanks in advance for the help!
Updated 9JUNE
I've also found this works:
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"personToDepartment = %#", selectedDepartment];
I'm also kind of newbie to CoreData, but it seems to me that predicate is wrong. According to Log record you're about to comparing personToDepartment.departmentName to a department Object. Predicate should look like:
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"personToDepartment.departmentName = %#", selectedDepartment.departmentName];
But there is a better way. selectedDepartment.departmentToPerson will return an NSSet with all persons belonging to this department (if relationship was set previously). But warning, if you'll try to NSLog(#"%#", selectedDepartment.departmentToPerson) probably you'll get "relationship fault", because CoreData will not do fetch until you address specific object in NSSet or enumerate through it. But for example NSLog(#"%d", selectedDepartment.departmentToPerson.count) will force CoreData to make fetch and you'll see number of persons in department.
UPDATE:
NSSet is empty probably because you are not setting relationship, when creating person's object. Inverse To-Many relationship from department to persons will be set automatically.
- (id)insertNewPerson:(NSDictionary *)personInfo inDepartment:(Department*)departmentObject
{
Person *personObject = [NSEntityDescription insertNewObjectForEntityForName:#"Person" inManagedObjectContext:context];
personObject.name = personInfo.name;
personObject.departmentName = departmentObject.name;
...
personObject.personToDepartment = departmentObject; //this is RELATIONSHIP, if set, then you can access all persons from specific department by doing: departmentObject.departmentToPerson
}

Core Data one to many record insert error

I have three entities
Forms{
name:string
jobs<-->>JSAjobs.form
}
JSAjobs{
name:string
form<<-->Forms.jobs
}
Jobs{
step:string
jobs<<-->Forms.jobs
}
I am getting this error:
to-many relationship fault "jobs" for objectID 0x95afe60. . . fulfilled from database. Got 0 rows
Now I save the row for Forms entity first later on I need to fetch the last record on the Form entity create a new row on JSAjobs with details on JSAjop like next
Thanks
NSMutableArray *jobData = [[NSMutableArray alloc]initWithArray:controller.jobData];
NSManagedObjectContext *context = [self managedObjectContext];
NSError *error;
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"JSAform" inManagedObjectContext:context];
[fetchRequest setEntity:entity];
NSPredicate *testForFalse = [NSPredicate predicateWithFormat:#"emailed == NO"];
[fetchRequest setPredicate:testForFalse];
NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:&error];
NSLog(#"Fetched Rows: %i", [fetchedObjects count]);
//NSManagedObject *existingParent= //... results of a fetch
JSAform *lastForm = [fetchedObjects objectAtIndex:0];
JSAjobs *newJobs = [NSEntityDescription insertNewObjectForEntityForName:#"JSAjobs" inManagedObjectContext:context];
// Setting new values
newJobs.jobType = [NSString stringWithFormat:#"%#", [jobData objectAtIndex:0]];
newJobs.jobName = [NSString stringWithFormat:#"%#", [[[jobData objectAtIndex:1]objectAtIndex:0] objectAtIndex:0]];
newJobs.comments = [NSString stringWithFormat:#"%#", [[[jobData objectAtIndex:1]objectAtIndex:0] objectAtIndex:1]];
newJobs.date = [NSDate date];
[newJobs setValue:lastForm forKey:#"form"];
if (![context save:&error]) {
NSLog(#"Whoops, couldn't save: %#", [error localizedDescription]);
}
//New SOP Value
JOBsop *jobSOP = [NSEntityDescription insertNewObjectForEntityForName:#"JOBsop" inManagedObjectContext:context];
for (int i = 0; i< [[jobData objectAtIndex:1]count]; i++){
NSLog(#"Value for key: %i", i);
if (i > 0){
for (int k = 0; k< [[[jobData objectAtIndex:1]objectAtIndex:i] count]; k++){
jobSOP.step = [[[jobData objectAtIndex:1]objectAtIndex:i] objectAtIndex:k];
[jobSOP setValue:newJobs forKey:#"jobs"];
// [NSNumber numberWithInt:[txtBoots.text integerValue]];
NSLog(#"Simple key: %#", [[[jobData objectAtIndex:1]objectAtIndex:i] objectAtIndex:k]);
}
}
}
if (![context save:&error]) {
NSLog(#"Whoops, couldn't save: %#", [error localizedDescription]);
}
enter code here
Your entities are very confusing because you did not pick usable entity names. You were too confused to lay out these simple relationships yourself. This results in chaotic code and does not allow you to think things through in a structured way.
Your code is completely incomprehensible. You have a data array despite a fetched results controller (presumably). The second part of your code sports a mysterious and cryptic new entity JOBsob. No way you can ask a meaningful question like this, let alone get an answer.
You have nested arrays without any type checking which is bound to break and in any way completely impossible to debug. Get rid of all of these.
Nevertheless, let's five it a try to get you started:
First, it does not make sense to use the plural for the entity name. If the entity represents a "form", it should be Form not Forms.
Maybe you want this setup:
Form <<----> Job <----->> JobDetail
One job has many forms and many job details. So the Form has a relationship job while the Job has a relationship forms. Similarly, a Jobdetail has a relationship job while Job has a relationship details.
When you have a form and create a new job you can only assign one job to it. Thus, the old job (if any) relationship would be broken.
oldForm.job = newJob;
This is a much safer way to assign relationships. Of course, you have created NSManagedObject subclasses for these entities for this purpose.
If however, the relationship between Job and Form is one-to-many in the other direction, your scheme would look like this.
Form <---->> Job <------>> JobDetail
I do not really now what a "form" would mean in this case - I will just rename it Project for clarity.
Project <---->> Job <------>> JobDetail
Now you can assign the a new job to a project and link the other relationships like this:
newJob.project = existingProject;
newJobDetail.job = newJob;

NSFetchedResultsController with NSDictionaryResultsType in NSFetchRequest

I have been looking over this issue since a week and haven't got any solution, so I thought to make the question more generalized, may be it will help the users to look into it and give me a solution.
Scenario:
I have an expense tracking iOS Application and I have a view controller called "DashBoardViewController" (table view controller - with FRC) which would basically categorize my expenses/incomes for a given week, a month, or year and display it as the section header title for example : (Oct 1- Oct 7, 2012) and it shows expenses/incomes ROWS and related stuff according to that particular week or month or year.
My Question:
What I want to accomplish is :
Show Distinct Results based on "Category" attribute of "Money" entity and calculate "Sum" based on the attribute.
But, my view controller called "dashboard view controller" is filled with NSFetchedResultsController with section name key path as "type" that can be an expense or an income. In order to get Distinct results, I shall use Result type as NSDictionaryResultsType in my fetch request which will give me unique results but FRC fails, it doesn't work with that. So, how will I get my section names then? I have posted the code below.
EDIT - BASED ON MARTIN'S SUGGESTION
- (void)userDidSelectStartDate:(NSDate *)startDate andEndDate:(NSDate *)endDate
{
AppDelegate * applicationDelegate = (AppDelegate *) [[UIApplication sharedApplication] delegate];
NSManagedObjectContext * context = [applicationDelegate managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
// Edit the entity name as appropriate.
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Money" inManagedObjectContext:context];
[fetchRequest setEntity:entity];
// Set the batch size to a suitable number.
[fetchRequest setFetchBatchSize:20];
NSPredicate *predicateDate = [NSPredicate predicateWithFormat:#"(date >= %#) AND (date <= %#)", startDate, endDate];
[fetchRequest setPredicate:predicateDate];
// Edit the sort key as appropriate.
typeSortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"type" ascending:YES];
dateSortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"date" ascending:YES];
if(self.choiceSegmentedControl.selectedIndex == 0)
{
choiceSortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"cat" ascending:NO];
}
if(self.choiceSegmentedControl.selectedIndex == 1)
{
choiceSortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"vendor" ascending:NO];
}
if(self.choiceSegmentedControl.selectedIndex == 2)
{
choiceSortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"paidBy" ascending:NO];
}
NSArray * descriptors = [NSArray arrayWithObjects:typeSortDescriptor, dateSortDescriptor,choiceSortDescriptor, nil];
[fetchRequest setSortDescriptors:descriptors];
[fetchRequest setIncludesSubentities:YES];
NSError * anyError = nil;
NSArray *propertiesToFetch = [[NSArray alloc] initWithObjects:
[entity.propertiesByName objectForKey:#"cat"],
nil];
[fetchRequest setReturnsDistinctResults:YES];
[fetchRequest setResultType:NSDictionaryResultType];
[fetchRequest setPropertiesToFetch:propertiesToFetch];
NSArray * objects = [context executeFetchRequest:fetchRequest error:&anyError];
for (NSDictionary *d in objects)
{
NSLog(#"NSDictionary = %#", d);
}
NSSet *uniqueSet = [NSSet setWithArray:[objects valueForKey:#"cat"]];
uniqueArray = [NSMutableArray arrayWithArray:[uniqueSet allObjects]];
self.categoryArray = uniqueArray;
if(_fetchedResultsController)
{
[_fetchedResultsController release]; _fetchedResultsController = nil;
}
_fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:context sectionNameKeyPath:#"type" cacheName:nil];
//self.fetchedResultsController.delegate = self; in order to stop "change tracking"
if(![_fetchedResultsController performFetch:&anyError])
{
NSLog(#"error fetching:%#", anyError);
}
[fetchRequest release];
//Finally you tell the tableView to reload it's data, it will then ask your NEW FRC for the new data
[self.dashBoardTblView reloadData];
self.startDate = startDate;
self.endDate = endDate;
}
With this code, SECTION NAME KEY PATH is not working and it's complaining that the object will be placed in unnamed section.
A fetched results controller does not support change tracking (i.e. the FRC delegate is set) in combination with a fetch request with NSDictionaryResultType.
The reason is documented with the setIncludesPendingChanges: function:
Special Considerations
A value of YES is not supported in conjunction
with the result type NSDictionaryResultType, including calculation of
aggregate results (such as max and min). For dictionaries, the array
returned from the fetch reflects the current state in the persistent
store, and does not take into account any pending changes, insertions,
or deletions in the context.
Change tracking of the FRC implies includesPendingChanges = YES for the fetch request, and that does not work with NSDictionaryResultType.
One workaround could be to use a FRC without change tracking, so you do not set the FRC delegate. But that means that to update your table view, you have to
save the managed object context, and
call performFetch on the FRC and reloadData on the table view.
Another workaround could be to use the FRC to fetch all sections and rows without the sum aggregation, and use the results to compute new table rows with the aggregation in memory (e.g. in controllerDidChangeContent).
UPDATE: (From the discussion) Another important point is that if you use a fetch request with NSDictionaryResultType, then the sectionNameKeyPath of the fetched results controller must be included in the propertiesToFetch of the fetch request.

Core Data NSMutable Set trouble

Ok I am trying to grab a NSMutable Set. Yes I have a previous post on this but this is slightly different. I have A player entity and a team entity. It is set up as a one to many relationship... On a different view controller I added players to the team. Now I am trying to get that teams players to show up on a table view... I am fetching the information as follows.
- (NSFetchedResultsController *)fetchedResultsController {
if (_fetchedResultsController != nil) {
return _fetchedResultsController;
}
NSString *entityName = #"Team";
NSLog(#"Setting up a Fetched Results Controller for the Entity named %#", entityName);
// 2 - Request that Entity
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:entityName];
AppDelegate *delegate = [[UIApplication sharedApplication] delegate];
_managedObjectContext = delegate.managedObjectContext;
// 4 - Sort it
request.sortDescriptors = [NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:#"players"
ascending:NO
selector:#selector(localizedCaseInsensitiveCompare:)]];
// 5 - Fetch it
self.fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:request
managedObjectContext:self.managedObjectContext
sectionNameKeyPath:nil
cacheName:nil];
_fetchedResultsController.delegate = self;
return _fetchedResultsController;
}
Then on my cell for row at index path I am setting the Player object to the fetched results as follows
Player *p = [_fetchedResultsController objectAtIndexPath:indexPath];
Then, I am setting the title of the cell like so.
cell.textLabel = p.firstName;
I am getting the error
reason: 'to-many key not allowed her
I am wondering what am I doing wrong???
Figured it out! I was sorting on a one to many relationship which is a NO NO in Core Data. I switched to sort on the player object and added a predicate to find the proper players I needed.

Resources