This time I get a strange behavior with NSFetchedResultsController. I create a fetchRequest like this:
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entdesc = [NSEntityDescription entityForName:#"Exam" inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entdesc];
NSPredicate *predi = [NSPredicate predicateWithFormat:#"student == %#", self.student];
[fetchRequest setPredicate:predi];
If I execute it with executeFetchRequest:error: of NSManagedObjectContext, I get the expected Result. All Exams according to the student. (Between Student and exam is a one-to-many relationship)
But If I use the same fetchRequest in a NSFetchedResultsController, I get something different. Until now I didn't get out, what I exactly get. In my eyes the result is random.
Can you help me? I want to manage the exams of a given student with a NSFetchedResultsController.
Sandro Meier
If you have a Student object already in hand, you don't have to fetch the Exam objects you just ask the Student object for the contents of its exams relationship. There is no need to fetch because you already have a reference to all the Exam objects you want.
As to why the fetch works outside the fetch results controller, I can't say with certainty. The controller does nothing but take the results of a fetch and package them for display in a tableview. If the data does not display properly in the tableview, then the problem is most likely in the tableview delegate/datasource methods where you connect the contents of the fetched results controller to tableview.
Related
I'm looking to display data from a Core Data model in a UITableViewController. Model has two entities, with a one-to-many relationship. I want the items from the many entity to be the rows, broken down into sections by the one. In the event no rows exist, I still want the section header to display.
I have a working NSFetchedResultsController table working for the many table only, but I need to expand it to the one-to-many relationship. I'm having no luck making that work, and haven't found any examples on how to do this.
The table will display all items, not a subset.
Any suggestions?
Since you didn't provide any details about the model objects your using, my example will use the following model.
The first thing I would suggest doing is look at the documentation for NSFetchedResultsController, specifically initWithFetchRequest:managedObjectContext:sectionNameKeyPath:cacheName:. it tells you everything you need to know about fetching you data into sections.
The important part is that the first sort descriptor must return a similar order as the sectionNameKeyPath.
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:#"Book"];
NSSortDescriptor *librarySort = [[NSSortDescriptor alloc] initWithKey:#"name" ascending:YES];
NSSortDescriptor *bookSort = [[NSSortDescriptor alloc] initWithKey:#"title" ascending:YES];
[fetchRequest setSortDescriptors:#[librarySort, bookSort]];
NSFetchedResultsController *controller = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
managedObjectContext:context
sectionNameKeyPath:#"library.name"
cacheName:nil];
How to obtain an ordered list of coredata managed objects via accessing them via a relationship?
That is:
have the following entities: LIST, LIST_ITEM (includes an 'Order' field), and ITEM.
assume that I have already fetched the list I want to work with
I can then use the coredata relationships to get the LIST_ITEMS via using the relationship: e.g. "list1.listItems", and then for each of these LIST_ITEMS I can get the ITEM ("listItem1.item")
But if I really just want, from the LIST, an ordered list of ITEMS from the list, based on the "Order" field in the LIST_ITEM, what is the easiest way of doing this?
You can sort the items returned by the relationship using an NSSortDescriptor just as you would in a regular fetch request. For example:
NSSortDescriptor *sortDescriptor = [[[NSSortDescriptor alloc] initWithKey:#"order" ascending:YES] autorelease];
NSArray *sortedListItems = [list1.listItems sortedArrayUsingDescriptors:[NSArray arrayWithObject:sortDescriptor]];
The key method here is [NSSet sortedArrayUsingDescriptors:]
I think that I understand the question correctly, but I think the best way to get lists from CoreData is create a compoun predicate and then search for items that way. For example if I am looking for only Events (entity) on a certain day, for a specific User (another entity). Then I can create an NSFetchRequest for the Event entry and specify and NSPredicate in the form of (user.name==%#) AND (event.date==%#) specifying the user's name and date
As I am fairly new to CoreData and coming from a MySQL-DB background, the CoreData Moddeling is kind of hard to understand at some point. I am sure you can help me out with this basic question.
CoreData model-descripton:
My database-model basically consists of two entities. The first one is called "Manager", the second one is called "Zipcodes". The "Manager" has 3 attributes, which are negligible at the moment. The important thing in my opinion is here the relationship called "zipcodes". The "Zipcodes"-Entity has an attribute called zip, which is a 16 int. It has a relationship as well, called "manager".
No I'll get to the point: Each manager has multiple zicodes in which he is responsible for all sales. The problem is now that I've setup an manager entity and want to link multiple ziplcodes to him. The zipcodes per manager are seperated in one comma seperated string. (12345,56789,...)
First of all I am creating an Manager Entity.
Manager *manager = [NSEntityDescription insertNewObjectForEntityForName:#"Manager" inManagedObjectContext:self.managedObjectContext];
The next step is seperating all zicodes to an array.
Manager *manager = [NSEntityDescription insertNewObjectForEntityForName:#"Manager" inManagedObjectContext:self.managedObjectContext];
NSArray *zipcodesArray = [[dict objectForKey:#"zipcodes"] componentsSeparatedByString:#","];
for (NSString *zip in zipcodesArray) {
???
}
So now that's the point where I am stuck. As later on I have to check the zipcodes via a searchBar they should be separated in the database. Do I now have to create a managedObjectModel for each zipcode? How do I connect all of them with the "one" manager entity? I'am sure there is a way to achieve that but I don't really know how.
Hopefully my question is understandable. If there's anything you would like to know, feel free to ask.
Thank you guys!
for (NSString *zip in zipcodesArray) {
NSManagedObject* zipcode = [NSEntityDescription insertNewObjectForEntityName:#"Zipcode"
inManagedObjectContext:self.managedObjectContext];
[zipcode setValue:zip forKey:#"zip"];
[zipcode setValue:manager forKey:#"manager"];
}
By establishing the relation from the zipcode to the manager on the last line, Core Data will automatically take care of inserting the zipcode into the relation from the manager back to the zipcodes.
Create a managed object instance of Zipcode. Set that object's zip attribute to the value of the string from your zipcodesArray. When you're done, save the managed object to your data store, check for errors, and repeat until you've walked all the way through your zip code array.
I have a core data model with two tables (meal and ingredients). I am trying to save ONE meal with MANY ingredients. I have the code below which loops through an array of ingredients. I'm trying to save it, but I cannot redeclare the "entity" below. How do I do it? I've tried releasing it, but that didn't work! Thanks for any help.
for (x=0;x<ingredients;x++) {
NSEntityDescription *entity = [NSEntityDescription insertNewObjectForEntityForName:#"Ingredient" inManagedObjectContext:managedObjectContext];
entity.name = #"test";
}
(this method does work saving ONE record out of the loop.. so that's not the problem)
You don't insert entities into contexts. You insert managed objects into contexts.
You should have something like:
NSManagedObject *myMO;
for (x=0;x<ingredients;x++) {
myMo = [NSEntityDescription insertNewObjectForEntityForName:#"Ingredient" inManagedObjectContext:managedObjectContext];
[myMO setValue:#"test" forKey:#"name"];
}
Of course, if have an NSManagedObject subclass you can just set the 'name' property directly.
The important thing is not confuse entities with instances of NSManagedObject or its subclasses. Entities are just descriptions of how objects relate to each other inside the object graph of the managed object context. The context uses the entity descriptions to figure out how all the actual instances fit relate to one another and how they are fetched and stored.
I need some guidance with this issue I have. I have a navigational Controller, with the root controller making use of CoreData and an NSFetchController. Now, the root controller works fine. When I click on an item, hierarchically it should display the next UITable associating the values for the row in the previous root controller.
Now, I am not sure what I should pass as a property to the next UITableViewController. Should it be an array, or should I pass the NSFetchedResultsController? THere will be another level in the hierarchy after the second, as a point of note.
Thanks
Doron
You have a couple options, at least:
Pass a reference to the managed object controller from parent view controller to child view controller; or,
Make the MOC property available from the app delegate, which is available to any view controller
Some prefer the second option as you may reuse and rearrange view controllers into different hierarchies. By disconnecting the MOC from parent and child controllers, you gain a bit more design flexibility. Also, if your application needs to manage more than one persistent store concurrently, then getting access from one central point to make multiple MOCs reduces code complexity.
Once you have the MOC in its view controller, you can create your fetched results controller in that view controller and apply operations in their own threads.
EDIT
It sounds like you have a one-to-many relationship between Site and Post (i.e. one site entity has many post entities).
Your "Posts" list view controller could include a site managed object, siteID managed object ID, or a siteName string property.
When you push the "Posts" list VC, set its site or siteName property and configure the request predicate accordingly.
For example, your fetch request's predicate should include something like site.name LIKE '%#' in it, e.g.:
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Post" inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];
NSPredicate *requestPredicate = [NSPredicate predicateWithFormat:[NSString stringWithFormat:#"(site.name like '%#')", self.site.name]];
[fetchRequest setPredicate:requestPredicate];
// ...
Or you could compare on managed object IDs, which is generally better for unique comparisons:
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Post" inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];
NSPredicate *requestPredicate = [NSPredicate predicateWithFormat:[NSString stringWithFormat:#"(site = %#)", self.siteID]];
[fetchRequest setPredicate:requestPredicate];
// ...
In both cases, you have filtered your Core Data store to match all Post entities that have a site name or a site managed object ID equivalent to your criteria.
Once you perform the fetch, these entities generally reside in an NSSet* or NSArray* that you can easily use as a UITableView data store, especially if you are using a fetched results controller.