Model structure when entities having some properties in common - ios

I have 2 entities in Core Data which have some common properties. I have to show both the entities in a same list view. What will be the best practice to do this? Can I do some inheritance thing and put common properties in base class?

Core Data supports inheritance.
Open your core data model and select the child entity. Make sure the utilities pane is displayed (top right button in Xcode) and select "Show the data model inspector" (right most icon in the utilities pane).
Here you can select a parent entity for your entity. All attributes of the parent will be available in the child entity.
Apple documentation on Core Data inheritance

What will be the best practice to do this?
It depends on what type of entities you need to model. For example, if you have a Cat and a Dog, you should move the attributes in common in a base entity (say Animal or whatever you want). In other words, you should have a reason for doing this, i.e. entities have a sort of relationship each others.
Can I do some inheritance thing and put common properties in base class?
Yes of course. In a model you are allowed to have a sort of inheritance pattern like the following.
where
I would stress two things here.
First, you can make base entity as an Abstract Entity. In this way, you are not allowed to create instances of this entity.
As per the doc.
You can specify that an entity is abstract—that is, that you will not
create any instances of that entity. You typically make an entity
abstract if you have a number of entities that all represent
specializations of (inherit from) a common entity which should not
itself be instantiated. For example, in a drawing application you
might have a Graphic entity that defines attributes for x and y
coordinates, color, and drawing bounds. You never, though, instantiate
a Graphic. Concrete sub-entities of Graphic might be Circle, TextArea, and Line.
Second, under the hood Core Data will create a single table with all the attributes you have inserted. So, if you have a lot attributes, you will have a lot of columns for a table.

Related

Core Data design principles

I just started reading this guide: https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/CoreData/KeyConcepts.html#//apple_ref/doc/uid/TP40001075-CH30-SW1
And it basically has (in my opinion) two big contradictions:
I get them both, but basically, if I follow the first "implement a custom class to the entity from which classes representing subentities also inherit"-statement, then ALL my entities will be put in the same table. Which could cause performance issues, according to the NOTE.
How big of a performance hit would I run into of it create a "custom super entity"?
You can use the inheritance mechanism to get a default database structure. From your link:
If you have a number of entities that are similar, you can factor the common properties into a superentity, also known as a parent entity.
There is no contradiction. The documentation is just telling you what the database structure is going to be when you use a certain facility. (And it is the standard database table idiom for inheritance.) Using the entity inheritance mechanism automatically declares and implements default parent-child class inheritance functionality along with a parent table. Otherwise you do any parent-child class inheritance declaration and implementation by hand. Each comes with certain performance and other characteristics.
Design involves tradeoffs between costs and benefits over multiple dimensions. "Performance" itself involves multiple dimensions, and has no meaning outside of given application usage patterns. Other dimensions relevant here include complexity of both construction and maintenance.
If you query about entities as parents sufficiently frequently then it can be better to have all parent data in its own table. But if you sufficiently rarely ask for the parent data while querying about a given child type or if you sufficiently frequently need both child and parent data then it can be better to only have parent data in the child tables or table. But notice that each design performs worse at the other kind of query.
The first is talking about sub-entities. The second is talking about subclasses. These are 2 different hierarchies.
One use for sub-entities is if you have a table where you want to show cells displaying different entities. By making them sub-entities, you can fetch the parent entity and all sub-entities will be returned. This is actually how the Notes app shows the "All Notes" cell above folders, that is actually displaying the Account entity, and both Account and Folder are sub-entities of NoteContainer which is what is fetched. This does mean all of the rows are in the same table, but personally I have not experienced any performance problems but it is something to keep in mind when modifying the entities in other ways like indexes, relations or constraints for example.
I'm not familiar with this quirk of SQLite, but modeling base class/subclass relationships are usually done with different tables. There is one table that represents the base class which contains attributes common to all derivative classes (Vehiclea) and a different table for each subclass which contain attributes unique to that subclass (Cars, Trains, Airplanes).
Performance is no better or worse than any entity normalized across different tables.

Core Data Model

I'm struggling with creating a suitable Core Data model for my app. I'm hoping someone here can provide some guidance.
I have two entities -- "Goals" and "Items". The Goals entity contains only a goal description, but any goal may have any number of subgoals, and these may extend multiple levels in a tree structure. Subgoals are to be contained within the same entity, so presumably the Goal entity will contain a pointer to "parent" which will be the parent goal of any subgoal.
There will also be an "Items" entity that contains a couple of text fields and a couple of binary items, and must be linked (ideally, by a unique identifier, perhaps objectID) to the particular goal or subgoal the item(s) are related to.
I am totally fumbling with how to set this model up. I know what attributes need to be in each entity, but the relationships, particularly between goals and "subgoals", has me stumped. I don't seem to be able to turn up any good examples of tree structures in Core Data on the Internet, and even the couple of books I have on Core Data don't seem to address it.
Can anyone here help an old SQL programmer get headed the right direction with these relationships in Core Data? Thanks.
Have you tried creating a one-to-many from Goal to itself, and a one-to-one from Goal to Item? The only thing I would worry about here is circular references.
Also, read Relationships and Fetched Properties in the CoreData Programming Guide.
Here is how it is done:
You set up a to-many relationship from Goal to Item in the model editor. Don't use any ids, foreign keys etc. This is old-fashioned database thinking - you can forget about it. Here we are only dealing with an object graph. The database layer is just an implementation detail for persisting the data.
Make two more relationships in entity Goal to itself: a to-one called parent, a to-many called subGoals. Make them the inverse of each other. Simple!
QED is correct, you can create a to many relationship on goal (call it subgoals) as well as a to-one relationship on goal (call it parentGoal) and set them as inverses to each other.
Then create another to many relationship (call it items) on the goal entity, with the inverse being a to one relationship on the item entity (call it goal). Then you're all set. You don't need to link items with a unique id, just add them to the items relationship.
Also note that if you did want to give items a unique id, do not use the objectID. The objectID should only be used as a temporary id as they are not guaranteed to remain the same. In fact they will change if you ever do a Core Data migration.
One way, though not really great, is to create a another entity, say subGoal, and each goal has one subGoal and each object of subGoal has many goal.

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

Inherit from SPManagedObject

In Simperiums iOS/OSX tutorial you say, each modeled object should inherit from SPManagedObject.
I didn't try it yet, but doesn't that lead to one big table in the SQLite database that contains a union of all fields of all modeled managed objects?
Yes, under the hood Core Data will tend to create a bigger table. Generally performance will suffer more from relations though, not inheritance:
Using Parent Entity in CoreData Models
We've done integrations with fairly complex inheritance hierarchies and didn't see any immediate issues with a fair amount of data.
Having said that, should you need more control over your table structure, you can avoid having a single parent for all your objects and instead either:
Manually add the ghostData and simperiumKey attributes to the objects you want to sync, and ensure their class is SPManagedObject (or ensure their custom class inherits from SPManagedObject), or
Create more than one parent entity with ghostData and simperiumKey attributes, and inherit from those for the parts of your model where it makes sense, depending on how you'd like the underlying tables to be structured.

Is it difficult to manage iInheriting a client dataset from another?

Say I have a client dataset CDSPerson that acts as a wrapper around a Persons database table. Say I have another table, PersonBenefits, that joins 1:1 back to the Persons table.
Say I wrap a Delphi class around CDSPerson, PersonClass, and another class around CDSPersonBenefits, PersonBenefitsClass, to read and write records. PersonBenefitsClass inherits from PersonClass so it can provide data from both tables. I'd like to be able to write data back to either table through PersonBenefitsClass.
Has anyone developed a clean way to handle the SQL query, provider flags and commit logic in the inherited class so that (a) fields stay aligned with the parent class and (b) both database tables can be updated?
Is there a reference for this that I can't find? Is this just a bad idea? I'm using Delphi 2007.
If you're going to develop a business-object-to-database mapping framework, (commonly known as ORM, Object-Relational Mapper,) you're going to need to put in a bit of architecture to make relationships like this work properly. Here's one way to do it:
PersonClass and BenefitsClass both inherit from BusinessObjectClass. BusinessObjectClass is a base class that contains the general logic to interact with the dataset. It has a list object of some sort that contains a list of relation objects.
Each relation object is a special object that contains either one or a list of BusinessObjectClass descendants, plus extra data describing the foreign-key relationship between the two tables. When BusinessObjectClass does its queries and its updates, it needs to iterate through all its relation objects and have them do their own queries and updates as appropriate.
In your composite object, (PersonWithBenefitsClass,) in the constructor, call inherited and then set up a relation object that describes the related BenefitsClass. Make sure that any inserts of new objects are done in the right order to preserve referential integrity.
That's the basic idea. (One basic idea. There are probably plenty of other ways to do it.) I'll leave the details of exactly how you implement it up to you.

Resources