Core data one-to-one unidirectional relationship - ios

I have 2 entities in which totally 12 properties are there of 3 variations of min, max and average of some particular type of fields. Hence I refactored the 2 entities into 3 entities making the 3rd entity as 'Values' which contains 3 properties i.e min, max and average. And reduced the 12 properties into 4 relationships. Here's a replica of my models as an example in the image below.
As you can see I have one-to-one unidirectional relationship with the 3rd entity. However Xcode keeps on complaining about 'Inverse' relationship.
As per me I can add 4 relationships in 'Values' and update all to become 'inverse', however this doesn't seem to be the right solution as when the second entity gets tied to the 'Values', it will have additional 3 nil relationships and whereas in case of first it will have 1 additional nil relationship. Both of these are unnecessary.
Refactoring 'Values' and splitting it into two similar entities also is not a good solution either I believe.
Hence can anyone suggest me what is the right approach or best practice to solve this problem. Let me know if I'm unclear anywhere while describing my issue.

Based on your description, I would undo the refactoring and go back to using properties instead of relationships. You're adding complexity for no real benefit, and the Values entity is (as you're finding) too generic to really be useful or meaningful. This refactoring isn't serving any useful purpose; don't fix it, revert it.

You should look into Weak Relationships (Fetched Properties) for how to manage relationships correctly and the solution for your error code.
Most object relationships are inherently bidirectional. If a
Department has a to-many relationship to the Employees who work in a
Department, there is an inverse relationship from an Employee to the
Department that is to-one. The major exception is a fetched property,
which represents a weak one-way relationship—there is no relationship
from the destination to the source.
Also, if you want to make things easier, you should look into (if possible) avoid 3 objects and have a single object, or two objects, with the propertiesToFetch of the NSFetchRequest in mind. This way you can fetch your Entity , keep the properties in a single Entity, but only fetch the properties you want and avoid the overhead and memory consumption of fetching properties you are not going to use.
Whichever fits your needs, you have the options. GL

Related

Best Way to Store Contextual Attributes in Core Data?

I am using Core Data to store objects. What is the most efficient possibility for me (i.e. best execution efficiency, least code required, greatest simplicity and greatest compatibility with existing functions/libraries/frameworks) to store different attribute values for each object depending on the context, knowing that the contexts cannot be pre-defined, will be legion and constantly edited by the user?
Example:
An Object is a Person (Potentially =Employer / =Employee)
Each person works for several other persons and has different titles in relation to their work relationships, and their title may change from one year to another (in case this detail matters: each person may also concomitantly employ one or several other persons, which is why a person is an employee but potentially also an employer)
So one attribute of my object would be “Title vs Employer vs Year Ended”
The best I could do with my current knowledge is save all three elements together as a string which would be an attribute value assigned to each object, and constantly parse that string to be able to use it, but this has the following (HUGE) disadvantages:
(1) Unduly Slowed Execution & Increased Energy Use. Using this contextual attribute is at the very core of my prospective App´s core function (so it would literally be used 10-100 times every minute). Having to constantly parse this information to be able to use it adds undue processing that I’d very much like to avoid
(2) Undue Coding Overhead. Saving this contextual attribute as a string will unduly make additional coding for me necessary each time I’ll use this central information (i.e. very often).
(3) Undue Complexity & Potential Incompatibility. It will also add undue complexity and by departing from the expected practice it will escape the advantages of Core Data.
What would be the most efficient way to achieve my intended purpose without the aforementioned disadvantages?
Taking your example, one option is to create an Employment entity, with attributes for the title and yearEnded and two (to-one) relationships to Person. One relationship represents the employer and the other represents the employee.
The inverse relationships are in both cases to-many. One represents the employments where the Person is the employee (so you might name it employmentsTaken) and the other relationship represents the employments where the Person is the Employer (so you might name it employmentsGiven).
Generalising, this is the solution recommended by Apple for many-many relationships which have attributes (see "Modelling a relationship based on its semantics" in their documentation).
Whether that will address all of the concerns listed in your question, I leave to your experimentation: if things are changing 10-100 times a minute, the overhead of fetch requests and creating/updating/deleting the intermediate (Employment) entity might be worse than your string representation.

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

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.

Core Data multiple relationships to same entity

I've been studying Core Data quite a bit now, and I've now decided it's time to use it in a new project I'm doing.
Having never use it in a working project I've just come across a few issues I would like to get the communities feedback on.
I'm doing a location based application and I would like to store "outings" in my Core Data model, so for each trip I have some traditional information such as date, distance, description etc... But I also need to save location information which I'll need to plot some points on a map.
So I have a "to" and "from" object per trip, I've created a MapPoint entity with latitude, longitude and location name attributes. On my Trip entity, I've added a "to" and a "from" relationship who's destination is MapPoint.
But what do I do with the inverse property?
Because Xcode seems to give a warning it I leave it as "No inverse".
I needed to create 2 relationships on MapPoint to reference back to the Trip to the "to" and another relationship referencing the "from" relationship of Trip.
Is this correct ? I can't quite understand.
I have a similar issue with a User Entity where this is being used in several other Entities, should I be implementing an inverse relationship back to each Entity which uses User?
To keep Xcode happy it seems I need to create a relationship on User back to Trip, and back to other Entities I'm using such as an Upload, Picture entities etc... it seems to me disturbing to think a Trip has a User object, which would then have prepared to link back to an Upload/Photo... which has nothing to do with that Trip.
If you want to support inverse relationships for your to and from relationships, you can just add appropriate relationships to your MapPoint entity. Call them tripTo and tripFrom, or whatever seems appropriate to you, and set those as the inverse relationships for your to and from relationships, respectively.
As the docs explain, you're not required to model a relationship in both directions, but doing so makes life easier. What happens, for example, when a user is deleted? If you have a number of other entities related to User, then you need some way to figure out which objects were related to that user so that you can update them. If you have inverse relationships, Core Data can automatically update any related objects using the deletion rule (like nullify) that you choose. Without inverse relationships, it's up to you to fix up any related objects.
I'm not entirely familiar with Core Data, but I believe it has a form of entity inheritance.
You could make your MapPoint entity abstract and create a FromMapPoint and a ToMapPoint which inherit their attributes from the MapPoint entity.
Your Trip entity can then have two separate relationships - one to FromMapPoint and one to ToMapPoint with the appropriate inverses.
As I said - I'm no CD expert, so hopefully someone else can come along and validate/shoot-down this suggestion?
With a bit of digging I found that you can set the parent entity through the Data Model Inspector. I created this quick representation of what you've been talking about.
In my experience Core Data doesn't "require" you to have inverse relationships, but not having them leads to mysterious bugs, even if you make sure to keep your object graph consistent manually. At least I think that's what was causing the mysterious bugs.
The SQLite store uses inverse relationships to represent to-many relationships. For a to-many relationship foo from entity A to entity B, I would have thought it would create a separate table "foo" with a column A and a column B, with object ids appearing more than once in column A. Nope. It doesn't represent one-to-many relationships at all, it represents their inverses only, which are to-one relationships. It represents fooInverse as a column in entity B's table, containing object ids that correspond to A-type entities. So you must have an inverse. It seems that in simple cases Core Data can deduce what the inverse should be if you don't define it, and your to-many property works correctly. However in more complicated cases such as the one you describe, it falls over.

Resources