Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to force UNIDIRECTIONAL to-many relationship to persist

Tags:

ios

core-data

There is a problem with core data when a to-many relationship has no inverse. Changes made to the related property do not persist. This is a problem many of us have faced, as it can be found by googling.

This is to ask if some of you found a trick/workaround to achieve persistence, beside the obvious answer or adding an inverse relationship.

Background:

  • Even if unidirectional relationship are discouraged in the documentation, they are not forbidden. The doc only insists on responsibility incurred when having no inverse.
  • The reason of not wanting an inverse is outlined in the core-data doc: when you have a large number of items linked to one entity the inverse relationship is loading a large NSSet each time an item is added. Consuming memory, possibly more than allowed for no reason.

Example

In employees/department typical paradigm, if you have a huge number of employees able to belong to several departments, you need a to-many relationship from employee to department. You do not want the inverse because each time an employee is linked to a department, a (very) large NSSet must be loaded, updated and saved. Moreover if the department entity is never deleted, graph integrity is easy to maintain.

Please do not reply that this is a feature of core-data and that inverse relationship is mandatory. This is not stated as such and is more like a bug than a feature. Posting a bug report is not solving the point for current deployed systems.

Edit: The Join entity solution This edit is to give more light and discussion to Dan Shelly's answer proposal below.

First, to reply to your first, I'm not trying to have a many-to-many but a true unidirectional to-many. The very same page your linked has this text a bit below the one you quoted:

Unidirectional Relationships

It is not strictly necessary to model a relationship in both directions. In some cases it may be useful not to, for example when a to-many relationship may have a very large number of destination objects and you are rarely likely to traverse the relationship (you may want to ensure that you do not unnecessarily fault in a large number of objects at the destination of a relationship). Not modeling a relationship in both directions, however, imposes on you a great number of responsibilities, to ensure the consistency of the object graph, for change tracking, and for undo management.

That said your proposed solution of adding an join entity is a way to go if there is no solution to force core-data to generates and updates it automatically.

IMO, and for my use case, the join entity does not even need to have the relationship to Department. This to-one is useless and may be replaced by a property of the join entity keeping related Department information, like its objectID or other indexed property to reach it.

i.e:
DepartmentEmployee:
Properties: Dept_ix (integer)
Relationships: employee (to-one,nullify)

like image 827
Max_B Avatar asked Nov 25 '25 07:11

Max_B


1 Answers


This is a great question.

ButFirst thing first:
It clearly state in the documentation:

"Important: You must define many-to-many relationships in both directions—that is, you must specify two relationships, each being the inverse of the other. You can’t just define a to-many relationship in one direction and try to use it as a many-to-many. If you do, you will end up with referential integrity problems."

Never the less, Lets describe the issue (resulting database)
When defining a to-many relationship, the resulting database does not add an additional table to map the relationship.
It only sets a property on the entity at one end of the to-many relationship equal to the last item that referenced it.

Example:

Model:
Entity: Department
Relationships: NONE
Properties: name (string)

Entity: Employee
Relationships: departments (to-many,no-action)
Properties: name

Resulting Database:
ZDEPARTMENT:
Z_PK
Z_ENT
Z_OPT
Z2DEPARTMENTS (int)
ZNAME

ZEMPLOYEE:
Z_PK
Z_ENT
Z_OPT
ZNAME

This structure will obviously result in data inconsistency.

The solution will be to hold an entity: DepartmentEmployee modeling the to-many relationship in both directions but one of them would be unidirectional (Department -> DepartmentEmployee):

DepartmentEmployee:
Relationships: department (to-one,no-action), employee (to-one,nullify)

and you will have to maintain the table upon deletion of a department object.

Hope this made some sense :)

like image 50
Dan Shelly Avatar answered Nov 27 '25 22:11

Dan Shelly



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!