Core Data - save existing managed object and show it in an another view - iphone

I'm working on an table drill-down style iPhone app that has prepopulated data. I use Core Data and NSFetchedResultsController to populate the table views. In the last level of the table view which shows an item (managed object) I want my user to be able to select that item which should eventualy be shown in another view. That other view would be a kind of a favorite list (implemented in a tab view). The user would then have a choice of deleting or adding other items to the favorite list.
My model has three entities each representing one level of table view. Higher level entity has a to-many relationship to lower level entity and inverse relationships are to-one
How do I use the existing managed object (object in the last level of table view) to save it and show it in favorite list view? Should I create new entity and establish relationship between the two?

My model has three entities each
representing one level of table view.
That is thinking backwards. What you have is three entities that exist logically in a hierarchy and the hierarchy of views reflects that logical structure. The views exist to display the data, the data does not exist to display the views. It's an important concept to grasp and if you fail to do so, your application design will always be overly complex, fragile and hard to extend and maintain. The data model always comes first and the logical relationships within the data model itself and the users interactions with that data ultimately control the UI structure of the app.
It's an easy trap to fall into because the instructional materials always start with the interface first. However, in real app design, you start with the data model first and work forward to the interface.
In this case, if you want to store favorites of some entity you have two choices. If the entity being a favorite is part of the core relationship between data and the user and you only have one set of favorites, then you could legitimately add a boolean "isFavorite" attribute to the entity and then just fetch al the entities where "isFavorite==YES"; If you have multiple list of favorites then the best method would to to create a FavoritesList entity and then relate each favorites entity to the objects it is supposed to list.
If the favorites are a minor and peripheral part of the user's interaction with the data you could store the objectIDs in the user defaults.

Yes, you could create a new entity and store the relationship. It's not necessarily the only way to do it -- you could store pointers to your NSManagedObjects in a container like an NSMutableArray -- but if you want to remember that list for later (i.e. save it between launches), it might make the most sense to also store it using Core Data.

Related

Core Data object graph design decision

I am designing an app which tracks data on Game objects. Each Game has a name, a date and other attributes. The problem I am having arises because I want the user to be able to add more names (for example) to pick from in the application. (in this case from a UITableView). So the user is presented with a list of names to choose from, and if the one they want is not in the list, they can add one to the list.
My solution is that I currently have a second entity called GameName so that I can show the user a list of those game names to pick from when they are adding a new Game. I just call an NSFetchRequest on all the GameName objects and display them in the UITableView. There doesn't have to be a Game object created yet to do this.
My dilemma is that I want to know if this is a good practice. It seems that if I do it this way, I will end up having a lot of entities with just one attribute, for the sake of allowing the user to pick from and add to a customizable list.
I hope this makes sense. I can clarify anything upon request.
Your approach is fine, and is commonly used in database design. The entity you want to add is called a "domain table" in databases. See this page, in particular this paragraph:
In a normalized data model, the reference domain is typically specified in a reference table. Following the previous example, a Gender reference table would have exactly two records, one per allowed value—excluding NULL. Reference tables are formally related to other tables in a database by the use of foreign keys.
Of course, you probably want to have an optional relationship between the GameName and Game entities.

How to fetch a Restaurant by its menuId?

I have set up Core data in my application, with two entities: Restaurant and Menu. There are about 30 or so restaurants, and 6 menus. One menu can belong to several restaurants.
However, each Restaurant entity has a menuId field. Is there a way to retrieve the specific menu entity according to which menuId the Restaurant entity has?
I also have a problem with values being stored more than once, even though they are the same. How can I prevent that from happening?
I'm pretty new to Core data, so any best-practice tips would be appreciated!
Thanks!
You could use an NSFetchRequest to retrieve menus by their id, but it would actually be better to define a relationship from your Restaurant entity to your Menu entity (and vice-versa). Internally, that does pretty much the same thing as your menu id attribute, but it's much more convenient to use.
You're following a database approach, based on tables and IDs to link these tables. This is wrong in Core Data, you must follow a object graph approach and CoreData will transform it to a corresponding SQlite database in a manner completely transparent to you.
So given the entities °Restaurant" and "Menu" you will create:
- in the entity "Restaurant" a 1-to-many relationship to "Menu" called "menus"
- in the entity "Menu" a 1-to-many relationship to "Restaurant" called "restaurants"
You will just need to add each restaurant menu to the NSSet corresponding to the menus relationship for a given menu, and vice versa. As you can see in this way you don't need to care about IDs, but just the object relationships.
As far as repeated data, this depends on you. Normally you should have a way to identify the unicity of an object (e.g.: the menu name, the restaurant name) and then try to retrieve it from Core Data before adding it as a new object.

fetchedresultscontroller with two entities - predicate to target each entity?

My iPhone app has a summary page (UITableView) where I would like to show a quick overview and therefore I need to get info from several entities. It was suggested to create an abstract parent entity and have my two entities as children of this one. This do allow me to fetch the two entities using the one fetchedresultscontroller.
This works but I find that I need to filter the return a small bit. Because of the 'hack' above these entities have nothing in common so I need completely separate predicates.so from EntityA I would need "color = blue" and from EntityB "length >= 10". Because the entity I'm actually querying have none of these this doesn't work at all.
Is there a way to do this or what's the best approach here?
Niether the UITableView or the NSFetchedResultsController is designed to deal with more than one entity at a time. Moreover, it seldom makes any sense to try to do so. If you find yourself in such a situation, you probably need to rethink your data model design.
If entities are logically associated with each other then they should be linked by a relationship. If data from any two objects is to be displayed in the same tableviewCell without being gibberish then they must have some logical association and therefore should be linked by a relationship of some kind. To display in the table, you fetch one side of the relationship and then walk the relationship/s to find the other related objects.
If the logical association is strong, it should be defined as a formal relationship in the data model e.g.:
EntityA{
//... some attributes
b<-->B.a
}
EntityB{
//...some attributes
a<-->A.b
}
However, if the relationship is weak or transient, then you should use a fetched property to relate them. The fetched property dynamically searches for other entities based on a preprogrammed fetch.
EntityA{
creationDate:date
someBs--(creationDate=$FETCH_SOURCE.creationDate)-->B
}
EntityB{
creationDate:date
}
A key concept here is that Core Data is providing the entire model layer of your Model-View-Controller design. It is not just a dumb database but an active object graph that models both the data itself and its behavior. Once you have a properly designed data model, problems with the controllers and views resolve themselves automatically.
If i understand correctly, you can use notifications and send a dictionary of required information to the UITableView view controller class.

Core Data and Relationships

I have two objects, a Trip and a Place. A Trip represents a journey from one Place to another Place, ie. a Trip needs a fromPlace and a toPlace. So, this is a 1-to-2 relationship, but I need to know which is the "from" and which is the "to". I am not sure how to model this in Core Data. I have created two entities (Trip, Place), and now I want to setup the relationship(s) so I have a fromPlace and a toPlace. Do I need to add an extra field on the Place entity called isFrom, or similar?
If this was in a database, I would just have a id column on the Place table, and then two columns in the Trip table - fromPlaceId and toPlaceId. How do I achieve something similar in Core Data?
Do I need to add an extra field on the Place entity called isFrom, or similar?
Yes. It's better for you not to think of Core Data as a wrapper around a database; the database intuition sometimes gets in the way.
Don't first think in terms of database and then try to translate it into Core Data. While you're learning how to use Core Data, just think of it as a system of objects which can be saved into a file and persist between two launches of the app.
Then, from the point of view of object-oriented programming, you have a class Trip which has two instance variables fromPlace and toPlace of class Place.
You want to make it persist on a file. So you create an entity Trip which has two relations fromPlace and toPlace, both of which is of entity Place. That's it!
In more detail, fromPlace and toPlace in Trip are both to-one relationships. In Place, you make two to-many relationships, say tripsStartingHere and tripsEndingHere. Then you set tripsStartingHere as the inverse of fromPlace, and tripsEndingHere as the inverse of toPlace.

Set a relationship with Core Data

I have two entities that are connected through a one-to-many relationship, let's say CategoryEntity and ItemEntity. The relationship is optional for CategoryEntity (there can be categories without items), but required for every ItemEntity. At the app's loading, the Categories already exist in the store, and I want to import ItemEntities and connect them to the appropriate CategoryEntity.
Obviously executing a FetchRequest for each ItemEntity to find the matching category wouldn't be a good solution because there will be about 4000-6000 Items each time..
So, is there something more efficient I could do?
If you have correctly setup your Core Data model, then you have a to-many relationship from the Category entity to the Item entity, and an inverse to-one relationship from Item to Category. Also, you have a "cascade" delete rule for the to-many relationship and a "nullify" delete rule for the to-one relationship.
Assuming this, each time you insert an Item object, setting its Category relationship automatically inserts the Item into the corresponding Category. Deleting an Item automatically removes it from the corresponding Category.
On the Category side, removing a Category automatically removes all of the corresponding Item objects.
Therefore, when you fetch Items, you have already fetched for each Item object its corresponding Category object. You do not need do anything else. Note that, by default, you are not actually retrieving the Category object during the fetch: instead a fault is fired the first time you try to access the object and the object is retrieved at that time. This provides better performances if you do not plan to use immediately the Category object stored within the Item object just fetched. If you plan to use the Category object almost every time you fetch an Item, then you must use the NSFetchRequest methods
- (void)setReturnsObjectsAsFaults:(BOOL)yesNo
- (void)setRelationshipKeyPathsForPrefetching:(NSArray *)keys
to tell Core Data that you do now want faults and that you ask for prefetching your Category relationship.
When you say 'import' item entities, what do you mean? Are these in another Core Data store, defined in another format in a file somewhere, retrieved over the network?
One approach would be to fetch all the categories in one go and add them to an NSDictionary acting as a cache and keyed by some identifying value that allows you to perform a quick lookup. For each item entity that you instantiate during import (whatever that means), retrieve its category ID and then retrieve the Category MO from the cache. Set the relationship and then save. Even better, batch up a number of insertions and save every 10, 100 or 1000 to reduce IO overhead.