Core Data Relationships on Abstract Entities - ios

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"...

Related

Core Data model - entities and inverses

I'm new to Core Data and I'm trying to implement it into my existing project. Here is my model:
Now, there's some things that don't make sense to me, likely because I haven't modelled it correctly.
CMAJournal is my top level object with an ordered set of CMAEntry objects and an ordered set of CMAUserDefine objects.
Here's my problem:
Each CMAUserDefine object has an ordered set of objects. For example, the "Baits" CMAUserDefine will have an ordered set of CMABait objects, the "Species" CMAUserDefine will have an ordered set of CMASpecies objects, etc.
Each CMAEntry object has attributes like baitUsed, fishSpecies, etc. that point to an object in the respective CMAUserDefine object. This is so if changes are made, each CMAEntry that references that object is also changed.
Now, from what I've read I should have inverses for each of my relationships. This doesn't make sense in my model. For example, I could have 5 CMAEntry objects whose baitUsed property points to the same CMABait object. Which CMAEntry does the CMABait's entry property point to if there are 5 CMAEntry objects that reference that CMABait? I don't think it should point to anything.
What I want is for all CMAUserDefine objects (i.e. all CMABait, CMASpecies, CMALocation, etc. objects) to be stored in the CMAJournal userDefines set, and have those objects be referenced in each CMAEntry.
I originally had this working great with NSArchiving, but the archive file size was MASSIVE. I mean, 18+ MB for 16 or so entries (which included about 20 images). And from what I've read, Core Data is something I should learn anyway.
So I'm wondering, is my model wrong? Did I take the wrong approach? Is there a more efficient way of using NSArchiver that will better fit my needs?
I hope that makes sense. Please let me know if I need to explain it better.
Thanks!
E: What lead me to this question is getting a bunch of "Dangling reference to an invalid object." = "" errors when trying to save.
A. Some Basics
Core Data needs a inverse relationship to model the relationship. To make a long story short:
In an object graph as modeled by Core Data a reference semantically points from the source object to a destination object. Therefore you use a single reference as CMASpecies's fishSpecies to model a to-one relationship and a collection as NSSet to model a to-many relationship. You do not care about the type of the inverse relationship. In many cases you do not have one at all.
In a relational data base relationships are modeled differently: If you have a 1:N (one-to-many) relationship the relationship is stored on the destination side. The reason for this is, that in a rDB every entity has a fixed size and therefore cannot reference a variable number of destinations. If you have a many-to-many relationship (N:M), a additional table is needed.
As you can see, in an object graph the types of relationships are to-one and to-many only depending on the source, while in rDB the types of relationships are one-to-one, one-to-many, many-to-many depending on both source and destination.
To select the right kind of rDB modeling Core Data wants to know the type of the inverse relationship.
Type Object graph Inverse | rDB
1:1 to-one id to-one id | source or destination attribute
1:N collection to-one id | destination attribute
N:M collection collection | additional table with two attributes
B. To your Q
In your case, if a CMAEntry object refers exactly one CMASpecies object, but a CMASpecies object can be referred by many CMAEntry objects, this simply means that the inverse relationship is a to-many relationship.
Yes, it is strange for a OOP developer to have such inverse relationships. For a SQL developer, it is the usual case. Developing an ORM (object relational mapper) this is one of the problems. (I know that, because I'm doing that for Objective-Cloud right now. But I did if different, more the OOP's point of view.) Every solution is a kind of unusual for one side. Somebody called ORM the "vietnam of software development".
To have a more simple example: Modeling a sports league you will find yourself having a entity Match with the properties homeTeam and guestTeam. You want to have an inverse relationship, no not homeMatches and guestMatches, but simply matches. This is obviously no inverse. Simply add inverse relationship, if Core Data wants and don't care about it.

Xcode Core Data alternative to relationships without inverse for general-purpose types

I'm trying to be a "good little programmer" and implement inverses for all relationships in my core data model. However, I've come across a situation that makes this seem impractical.
For simplicity, consider a general-purpose entity type called Location that contains an x attribute and a y attribute (and might contain other attributes, but let's keep it simple). Several different entity types may need to keep up with one or more location (players have an original location and a current location, cells have locations, destinations have locations, etc). Given all the different uses for such a general type, it seems impractical to make an inverse relationship in the location entity type for every instance in which it's used in other entities.
Is there an better alternative in Core Data for implementing a very general-purpose entity type that would prevent the need for relations without inverses?
Having received no answers, I'll share the pattern I started using to help in this situation:
Basically, I derive an entity type from the general-purpose entity type for each specific use, and then I can make relationships and inverse relationships to the derived entity type as appropriate.
For example, I can have a PlayerLocation entity type and a PlayerOrigin entity type, both with the general purpose "Location" as their parent entity type (so in object-oriented-think, they become classes derived from a Location base class). Then a Player entity type can have a to-one relationship (location) to a PlayerLocation and a to-one relationship (origin) to a PlayerOrigin, and each of those derived location types can have unique inverse relationships (owner) pointing back to the Player. Here's a pictorial:
This may cause me to create many more entity types than I originally envisioned, but it makes for a pretty clean object model with specific entity types that have clear relationships and inverse relationships.
Hope that helps others.

Reason for setting relationships among entities in Core Data

After learning about relationships between entities in Core Data. I don't see the real reason for setting up relationship between two entities. They can be connected separately if one of the entities contains a property that can hold another entity by having a property of type NSManagedObject.
#property (nonatomic, strong ) NSManagedObject *AssetType;
This is a concept you must understand: Core Data is not a database but it is an object graph manager and, as a second functionality, offers persistence (e.g using for example a Sqlite store).
Said this, if you have two separated entities and you need to retrieve values based on the conditions that belong to the other entity, you need to run two requests and filter the results in memory. On the contrary if you set up a relationship you can just create a request wih a specific predicate and let Core Data to retrieve the correct results for you. In addition, through relationships you can access objects that belong to another entity as simple as accessing a property object. For example, the following snippet says that based on entityA I can access a property calles someRelationship that allows to retrieve one (or more) entities of type EntityB. If someRelationship has been set up as to-many you'll receive one or more EntityB entities.
entityB = entityA.someRelationship;
The real advice is to think in terms of objects graph!!!
Further reference: Core Data Overview by objc.io.
Update 1
The other big advantage is that relationships allow you to take advantage of deletion rules and, through inverse relationships, you are able to maintain the integrity of your graph.
See Relationships and Fetched Properties.

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).

Resources