NSFetchedResultController for an Entity and its relationships - ios

I have an Entity Person. Person has three relationships to Entity ObjectA, ObjectB, and ObjectC.
Can I use an NSFetchedResultController to sort them by type? So section 0 would be ObjectA's, section 1 would be ObjectB's, and section 3 would be ObjectC's? And further, can i sort them by name?
Or do I use 3 different datasources (either load them into an array or 3 different NSFetchResultController's)?

An NSFetchedResultController can only fetch one entity type at a time, so assuming ObjectA, ObjectB, and ObjectC are different entity types, then you'll need three NSFRCs.
If they are three different entity types, you might consider putting them under an abstract entity. Then you could create one NSFRC for that type (example here).

Related

Nesting Issue In Core Data

I have created a database in which I have to store contacts in various categories. The issue comes when I have to create Sub categories in a Category like :-
Categories ->
Sub Categories->
Contacts
But the Categories can also have Contacts like
Categories -> Contacts
where the sub categories can also have contacts. I figured that nesting in core data would be used. How can I achieve this kind of a relationship ? How do I save the sub categories into the categories even though they are of the same entity ?
I have attached my core data entity relationship model here :-
There is no problem creating a "self" referencing relationship in CoreDate.
In other words, An entity may have a relationship of its own kind.
The only difference in your case between a Category and a SubCategory is the existence of a parent entity.
So there is no need to define a new entity for that part.
You can simply define a relationship:
Category.parent of type Category (say to-one in this case)
and a reverse relationship of:
Category.subCategories of type NSSet (to-many in this case) containing Category objects.
You can set all that up in your interface builder.
Now, since Category has a relationship with Contact so does all the "sub-categories" will have that relationship.
If you like your "sub-categories" to have additional properties, simply create a new entity an make it inherit from your Category entity (keeping the above setting I described).
and add to it the new properties.

Performing the equivalent of a union with Core Data for a UITableViewController

I know union is a SQL construct, but it's the best analogue for what I'm trying to do.
I have multiple groups of data that I'm receiving from an external source. I'm maintaining them as separate entities in Core Data (they only have some attributes in common (e.g. name)), but I want to present them in the same tableView.
Say I have an entity Food that has relationships with FruitGroup and VegetableGroup. The FruitGroup has a relationship with Fruit which has a relationship with FruitType. The VegetableGroup is similar.
How can I use FruitGroup.Fruit.name and VegetableGroup.Vegetable.name as sectionTitles? And FruitGroup.Fruit.FruitType.name and VegetableGroup.Vegetable.VegetableType.name for row data. (I tried coming up with a predicate that walks down from Food, but that doesn't appear to be workable)
Example modeled data (my groups are far more disparate than fruits and veggies, so re-doing my data model is not an option):
Food
FruitGroup
Apple
Macintosh
Granny Smith
Pear
Bartlett
Asian
Anjou
VegetableGroup
Asparagus
white
wild
Peas
baby
split
Which I would like to appear as:
Apple [section]
Macintosh [row]
Granny Smith
Pear
Bartlett
Asian
Anjou
Asparagus
white
wild
Peas
baby
split
I could use multiple NSFetchedResultsControllers in the UITableViewController and conditionally select the FRC within each of the UITableViewDataSource methods, but that doesn't feel clean.
I'm thinking about subclassing NSFetchedResultsController and, internal to my subclass, merging the results of multiple private NSFetchedResultsControllers that each represent one of the entities. (e.g. sections returns a concatenation of the returns from the sections calls of the internal FRCs)
Does this make sense - or is there a better way? (I saw Core Data Union Query Equivalent but since there are relationships among my entities, I wanted to seek alternatives)
While you can do this as described in the other answers (via creating an abstract Parent entity), I would not recommend it. The performance when it comes to dealing with abstract parents gets bad very quickly. The reason for this is that Core Data will put all of the children into a single table in the underlying SQLite file.
I would suggest going a different route. Have a single entity called Food with attributes describing if it is a vegetable or fruit. Then you have one NSFetchedResultsController which has the type of the food item as the sectionPath and you will get your display the way that you want it.
I recommend creating entities in Core Data based on what the objects are as a very loose level. I would not create entities for Honda, Ford and Dodge, but create an entity for Car and perhaps type or a relationship to a manufacturer.
While Core Data can be backed by a database, at the end of the day it is not a database but an object graph and should be treated as such. Trying to normalize the database will result in poor performance of the object graph.
You should probably look into abstract entities. For example, you could create an abstract entity called Food. Then you're able to create Fruit and Vegetables, which inherits the abstract entity. You'll have to set Food as the "Parent Entity".
Then you could fetch all the items with the entity Food, which includes both Fruit and Vegetables. Based on your post, you'll probably will have a relation from Food to FoodGroup.
To answer your question:
You cannot unify different entity types (if they are not subclasses of the same entity) under a single fetch request. You can define an entity (B) to inherit from another entity (A) and then fetch by the parent entity (A) and get both kind of entities (As and Bs)
You can try and think of it this way:
Item ("Macintosh","White Asparagus",...) has a relationship to Group ("Apple","Asparagus",...), and Group has a relationship to Area (or simply to another parent group).
In this manner you could use a single FRC with sectionNameKeyPath of "group.name" and entity Item (you can filter by "group.area" to only select food items).

Search by properties of two Entities (fetch from two Entities)

Let's say I have two entities, A and B. My goal is to implement the search by all properties of A and just one property of B, and to display sum of search results in one tableView. Naturally I can set fetchRequest only by one entity. But if I am understand right I can fetch not only from A but from B too if they are connected with relationships.
So what do I need to do to implement this? Does default fetch fetches all properties from A and B? If not, how can I specify fetch of all properties from A and one property of B in one fetch?
Issue solved.
At the stage of preloading data from JSON file into Core Data I am define getters for properties (prefetching data from entity)in B and setting entity properties of A equal to returned results of this getters (all this in NSManagedObject subclasses inherited from entities). So after that I am able to fetch all what I need using this getters through appropriate properties.

Core Data Relationships on Abstract Entities

Is it legitimate to create a one to one relationship between two entities when one is set to be abstract ?
An abstract entity is not meant to be instantiated. That's why you cannot create such a relationship. What you could do though is to create a relationship where the entity(s) are inheriting from an abstract entity.
From Apple's docs:
A relationship specifies the entity, or the parent entity, of the
objects at the destination. This can be the same as the entity at the
source (a reflexive relationship). Relationships do not have to be
homogeneous. If the Employee entity has two sub-entities, say Manager
and Flunky, then a given department's employees may be made up of
Employees (assuming Employee is not an abstract entity), Managers,
Flunkies, or any combination thereof.
EDIT:
Apparently you could create such a relationship (so that child entities would inherit the relationship as well)...
If you define an entity inheritance hierarchy (see “Entity
Inheritance”), when you specify a super-entity as the entity for a
fetch request, the request returns all matching instances of the
super-entity and of sub-entities. In some applications, you might
specify a super-entity as being abstract (see “Abstract Entities”). To
fetch matching instances of all concrete sub-entities of the abstract
entity, you set the entity for fetch specification to be the abstract
entity. In the case of the domain described in “Abstract Entities,” if
you specify a fetch request with the Graphic entity, the fetch returns
matching instances of Circle, TextArea, and Line.
See also this answer: Core Data: Abstract Entity in Fetch Request
yes. you can have a person who owns a "thing"...

Core data and sorting after a join condition

I have 3 tables in my core data tables.
Item table: items, which has an ID column and a connection to a properties table.
Properties table: it has a propertyValue column and a connection to item table and a connection to property table.
Property table: it has a propertyName column and a connection to properties table.
The property table contains a propertyName called "price".
The properties table contains a propertyValue "20" for the property "price".
Do you think I can sort the Items table by price?
I am using a NSFetchedResultsController and I am creating a NSFetchRequest for it.
I have tried to write a NSSortDescriptor with a comparator block object for the NSFetchRequest. It isn't working. After this I tried to write a NSSortDescriptor without any selector or block object, I just setup a key called "dealPrice" and created a category on the Item managed object with a method called - (NSString *)dealPrice. It wasn't working neither.
Do you know any other method? Or do you know the solution?
You've obviously got a bad case of SQL fever. Your trying to treat Core Data like an SQL wrapper and that is messing everything up.
Core Data is not SQL. Entities are not tables. Objects are not rows. Attributes are not columns. Relationships are not joins. Core Data is an object graph management system that may or may not persist the object graph and may or may not use SQL far behind the scenes to do so. Trying to think of Core Data in SQL terms will cause you to completely misunderstand Core Data and result in much grief and wasted time.
A Core Data datamodel should not be configured depending on the needs of the UI or any other non-data requirement. Instead, it should accurately model/simulate the real world objects, events or conditions that the app deals with.
In this case, you are modeling:
A type of property that has a name and a price.
An item denoted by an id of some kind
A relationship between one or more particular property instances and one or more instances of item.
Therefore, your data model only needs two entities connected by a relationship. You don't need a "join" because the relationship handles the connection between the two entities automatically.
The simplest model has just a one-to-one relationship:
Item{
id:string
property<-->Property.item
}
Property{
name:string
price:number
item<-->Item.property
}
If each Item object can have several associated Property objects then you would have:
Item{
id:string
properties<-->>Property.item
}
Property{
name:string
price:number
item<<-->Item.properties
}
If each Property object can have several associated Item objects:
Item{
id:string
property<<-->Property.items
}
Property{
name:string
price:number
items<-->>Item.properties
}
How you configure your sort descriptors depends on the details of the relationships and which entity's objects your tableview will display.
What I would first recommend is to stop thinking about CoreData like a database. It is NOT a database. The things you call "tables" are actually Entities. Think of them as objects, that have properties and relationships to other objects. Think about making your data model as simple as possible. Do not try to optimize your structure for database performance etc. The actual backing schema is not under your control.
With that in mind, from what you've posted about your data model, it seems like you should be able to collapse into at least 2 entities instead of 3 (perhaps 1 but not sure without seeing your entire data model). Then, you should be able to do a simple fetch on the Items entity with a predicate that sorts on a property of it's related object.
It sounds like your real object model is and entity named Deal with an attribute named "price".

Resources