CoreData relationship confusion - ios

Suppose I have two entity named Book and Publisher
1. Book has attribute :- writer, title.
2. Publisher has attribute :- name, type
I set a relationship :- Publisher to Book ( one to many and set it as inverse relation)
With relationship selected I can see in DataModal inspector a row called Delete Rule with three options 1. Nullify 2. Cascade 3. Deny
What these are and I want to delete Publisher entity only if I delete the last Book
Thank You in advance.
I'm just a beginner
:)

The docs do a good job explaining these delete rules
https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/CoreData/HowManagedObjectsarerelated.html
Relationship Delete Rules
A relationship's delete rule specifies what should happen if an
attempt is made to delete the source object. Note the phrasing if an
attempt is made. If a relationship's delete rule is set to Deny, it is
possible that the source object will not be deleted. Consider again a
department's employees relationship, and the effect of the different
delete rules.
Deny If there is at least one object at the relationship destination
(employees), do not delete the source object (department).
For example, if you want to remove a department, you must ensure that
all the employees in that department are first transferred elsewhere
(or fired!); otherwise, the department cannot be deleted.
Nullify Remove the relationship between the objects but do not delete
either object.
This only makes sense if the department relationship for an employee
is optional, or if you ensure that you set a new department for each
of the employees before the next save operation.
Cascade Delete the objects at the destination of the relationship when
you delete the source.
For example, if you delete a department, fire all the employees in
that department at the same time.
No Action Do nothing to the object at the destination of the
relationship.
For example, if you delete a department, leave all the employees as
they are, even if they still believe they belong to that department.
It should be clear that the first three of these rules are useful in
different circumstances. For any given relationship, it is up to you
to choose which is most appropriate, depending on the business logic.
It is less obvious why the No Action rule might be of use, because if
you use it, it is possible to leave the object graph in an
inconsistent state (employees having a relationship to a deleted
department).
If you use the No Action rule, it is up to you to ensure that the
consistency of the object graph is maintained. You are responsible for
setting any inverse relationship to a meaningful value. This may be of
benefit in a situation where you have a to-many relationship and there
may be a large number of objects at the destination.

Related

Core Data Relationship For Unidirectional One to Many

What is the best practice for creating Unidirectional One to Many Relationships in Core Data?
For example...
Lets take two classic entity examples, "teacher" and "student".
Each student has one teacher, and each teacher has many students.
In CoreData right now you are forced to provide an inverse such that teacher is forced to have a reference to a 'student'. If you don't you get this nice warning that says something along the lines of...
file:///Users/josephastrahan/Documents/VisualStudioProjects/Swift3WorkOrders/WorkOrders/WorkOrders/WorkOrders.xcdatamodeld/WorkOrders.xcdatamodel/: warning: Misconfigured Property: Teacher.student should have an inverse
What if I don't want teacher to have a reference to student?
Some other posts have brought up that I should just allow the inverse anyways but I think this inverse may be causing an issue with one of my projects.
That said let me explain my exact issue.
Lets say that our teacher has a unique attribute int64 called 'id'. Lets say the students also have unique attribute int64 called 'id'.
The int64 is enforced to be unique by adding a constraint on the model for teacher on id. (refer to image below to see how that is done)
Every year there is new students but the teachers stay the same. So I decided that I want to delete all the students without deleting the reference to the teacher. So I set the delete rule to 'nullify' for the relationship for the teacher to student and 'nullify' for the student to teacher.
Now when I create a new student I want to assign one of the existing teachers to that student... (something like student.teacher = teacher object with id of 1 or the same id as before) however!! , because the teacher has the inverse relationship to a student that no longer exists (which in theory should be null) the program crashes!
I know this is the case as I've used print console logs to narrow it down the exact point that it occurs. Also I know this because if I add the delete rule of cascade for student the crash will go away but...then I lose my teacher! which I don't want...
Some things that I think might be the issue:
1.) When I do my testing I do it at the startup of the program which creates a new context everytime. Could it be that because I never deleted teacher it still thinks it refers to a student from a context that no longer exists? (if I'm even saying this right...)
I'm not sure the best solution to acheive what I'm trying to do with Coredata and any advice is much appreciated!
Note:
Forgot to mention I also have the Merge Policy of: NSMergeByPropertyObjectTrumpMergePolicy, which will overwrite the old data with the new. When I'm creating new students I'm creating new teachers also just using the same id which should follow this policy.
You are almost there.
The advice to keep the inverse relationship is a good one. Keep it.
Your issue is likely caused by different contexts. Instead of holding on to a teacher object in memory, you should fetch the teacher (based on the id) in the context in which you intend to use it.
Your nullified students should not have any impact. A to-many relationship is really a Set<Student>. Make sure the set is empty.
NB:
If you want to keep the student in the database (for historical purposes) - it seems from your description that this is the case - you might also consider another scheme: give your students another attribute (such as a year) and use that to filter the student list. You would not have to delete or nullify anything. You could also do some more interesting time-based queries on the data.
Unique Constraints are available with iOS9. Which have helped iOS Developers with adding and updating records in CoreData.
Unique Constraints make sure that records in an Entity are unique by the given fields. But unique constraints along with To-Many relationship leads to a lot of weird issues while resolving conflicts.
e.g. “Dangling reference to an invalid object.”
This post is basically focused to a small problem that may take days to fix.
http://muhammadzahidimran.com/2016/12/08/coredata-unique-constraints-and-to-many-relationship/

Understanding Core Data delete rules on One to Many

I am a little fuzzy about Core Data Relationships deletion rules. So if someone could help me answer a few questions about them.
I have Entities A and B. A has a to-Many relationship with B, and B has a to-One relationship with A.
A<--->>B
Now, if I set the delete rule at A to Cascade, I understand it will delete all the Bs related to it. But if I set it to Nullify, will it set the Bs to NIL or just the Foreign Key to Nil?
And I looked everywhere about the relationship from B to A, should I set it to Nullify? Will that just Nullate the "B Object" at A? Or will it Nullify all the Bs associated with A? What about Cascade? Will it delete all the Bs associated with A, or just the particular B?
Or do I just use "No Action" on the relation from B to A so that when I delete B, no change will happen to A, but the reference to B won't exist?
I am PRETTY confused with these, so excuse my questions.
Thanks.
If you set the delete rule to "nullify" and delete the A object, then the references to that object in the Bs will be removed. The inverse works the same way. If you have cascade and delete B then it will remove the A that B pointed to. It will then follow the delete rule from A to the remaining Bs (either cascade or nullify).
The rules you set really depend on your data model. If A were a customer and B were their orders then you could set the A->B rule to deny (prevent A from being deleted if it the customer has orders) or cascade (delete the orders when the customer is deleted). The B->A rule would probably be "nullify". If an order is deleted simply remove the reference to the order from the customer.
The relationship delete rules are described in the Apple Core Data Programming Guide
More deep explanation and visualization with delete rule.
Let be assume we have database with table person and work. Single person can have many tasks to do.
Sample data and ER relationship
Delete Rule Explation
No Action : If I add this delete rule on relationship and then delete one of the person then it will not do anything with the task but person got deleted. The task still points to the person that we deleted.
Use Case: I don't think it is used anywhere.
Nullify : If I apply this delete rule and delete the person then associate tasks will points to the null person. For example, I deleted the thor and thor tasks will point to the null person. Check below output.
Use Case : Let's assume we have DB with Person and address. Now person sells his house to broker. In this case you can null the person of that address and reassign the owner to that house when new Person purchased that house.
Cascade : In this rule, if I deletes the person then it will deletes all the tasks associated with that person. For example, I deletes the Spiderman, check below output.
Use Case: Let be assume we have a user and his friends list. If user account deleted then we also want to delete the friend list.
Deny : Now we have person i.e. IronMan with 2 tasks. In this rule, if I try to delete the Iron Man then it does not allow me to do. It gives error "The operation couldn’t be completed. (Cocoa error 1600.)" on saving the context. Now to delete the Iron Man person, we need to delete all his associated tasks and then we could able to delete the Person.
Use Case: Lets assume, there is a user with bank account. We can not delete the user from the bank until his account is not closed.
if you set "nullify" and delete A's object , A's object and the back relationship only will get deleted not B's object.
eg : Customer entity has nullify relationship to orders . and if you delete a customer from customer entity, it will just delete customer and its back relationship from order . it wont remove the orders the customer made
but if the relationship is "cascade" it will remove the customer and his orders .
if it is "deny" . if the customer has any order , it wont delete delete the customer even .

Exclude Models from being saved with Breeze

I have EntityA which has a navigation property to EntityB. In the frontend it's possible to create a new EntityA and append it to EntityB. If I now try to save the new created EntityA, Breeze also want's to save the changes on EntityB (containing the new ID of the newly created EntityA). Is it somehow possible to avoid having EntityB, because in this specific use case it should be possible to append new entities to EntityB, but these should not be saved back (and also not be reported as pending changes)?
I see the possibility with using two EntityManagers, but this would mean that I can no longer have navigation properties between the two types.
Pascal is asking an important question: are Entity A and Entity B related one-to-one? More to the point are they related one-to-one such that A depends on B (i.e. A is a child of B)?
A typical relationship of this sort is the "extension" entity. Consider "Order" and "OrderExtension". "OrderExtension" is a bolt-on type with optional fields that "extend" the core order data. An order can have zero or one "OrderExtension" records.
Order is the parent in this example; it SHOULD NOT have a FK reference to the OrderExtension. The OrderExtension is the child and it SHOULD HAVE a required OrderID FK field. The parent Order can exist without a child, but the child OrderExtension cannot exist w/o the parent.
At least that's how I think it should be. I've often seen folks turn this around. They give the Order an OrderExtensionID FK field which is optional. The OrderExtension has no backpointer to the Order.
The weakness of this design is that it allows you to create multiple orphaned OrderExtension entities that don't belong to anything ... and you'll rarely know they are there.
I'm betting that's your situation. I'm betting that Entity B is like OrderExtension and Entity A is like Order. When you created the OrderExtension (B) and associated it with an Order (A), Breeze tried to maintain that relationship for you by updating the Order.OrderExtensionID property. That puts Order (A) in a modified state.
DO not proceed until you've figured this out. While Jeremy is correct that you can save one entity by cherry picking the pending changes - you can save B without saving A -, you risk breaking the integrity of your data!
From a modeling perspective you've made Entity A dependent on Entity B. If you don't save A at the same time you save B, there will be no way for someone using the database to know that the two are related.
Next time you query for either of them, neither you nor Breeze will know they are related. You will be unable to navigate between A and B. I'm pretty sure that's not what you had in mind.
You can pass an array containing the entities you wish to save to the saveChanges method to restrict which entities are saved.
From the breeze docs:
saveChanges ( [entities] [saveOptions] [callback] [errorCallback] ) async
Saves either a list of specified entities or all changed entities
within this EntityManager. If there are no changes to any of the
entities specified then there will be no server side call made but a
valid 'empty' saveResult will still be returned.
Parameters:
[entities] Array of Entity optional The list of entities to save.
Every entity in that list will be sent to the server, whether changed
or unchanged, as long as it is attached to this EntityManager. If this
parameter is omitted, null or empty (the usual case), every entity
with pending changes in this EntityManager will be saved.

CoreData relationship , with Delete

If I delete a CoreData record from an entity, does that also delete the relationship that record had with another record in another entity?
It depends on the Delete Rule that you have enabled for the relationship. The Core Data Programming Guide documents these (extracted below). Have a look in the inspector to see which option you have set for your relationships. If you have a specific data model which you want comment on you should edit your question to be more specific.
Deny
If there is at least one object at the relationship destination, then the source object cannot be deleted. For example, if you want to remove a department, you must ensure that all the employees in that department are first transferred elsewhere (or fired!) otherwise the department cannot be deleted.
Nullify
Set the inverse relationship for objects at the destination to null. For example, if you delete a department, set the department for all the current members to null. This only makes sense if the department relationship for an employee is optional, or if you ensure that you set a new department for each of the employees before the next save operation.
Cascade
Delete the objects at the destination of the relationship.
For example, if you delete a department, fire all the employees in that department at the same time.
No Action
Do nothing to the object at the destination of the relationship. For example, if you delete a department, leave all the employees as they are, even if they still believe they belong to that department.

Modeling a one-to-many relationship in Core Data for iOS

I have two entities: patient and checkpoint.
Patient has attributes such as DOB, name, ID, etc.
Checkpoint has attributes such as dateRecorded, height, weight, etc.
You probably get the idea- I want there to be a set of patients, and then each patient can have checkpoints associated with that patient.
On both entities, how should I set the settings? The settings are:
I looked at the documentation for this, and I was still confused. I think what I want is a one to many relationship (for patient), but then I'm not sure how to set the inverses for either of them, or the delete rule and the other stuff. THANK YOU!!
I just got started with Core Data this week. Great question!
Relationships:
Since one patient can have many checkpoints, the Patient to Checkpoint relationship is a One to Many relationship. The concept of an "inverse relationship" is essentially this: You've got a relationship going one way (Patient to Checkpoint) - now go ahead and look at it from the inverse, the Checkpoint's perspective. A checkpoint can apply to only a single patient. Therefore, the Checkpoint to Patient relationship is a One to One relationship.
Inverse Relationships:
To handle the inverse relationship, simply create each relationship, ignoring the inverse. Then, after you have the relationship on each object, go ahead and define the inverse as the relationship on the other entity.
In other words, a relationship points to another entity or a group of entities. An inverse relationship points to a relationship on another entity.
Delete Rules:
As far as delete rules are concerned, it's fairly simple. When trying to delete a patient which has checkpoints...
Deny: Core Data won't let you delete the Patient.
Cascade: Core Data will delete the Entity (Patient), as well as cascading through relationships and deleting those objects as well. (In other words, Core Data will delete the Checkpoint objects too.)
Nullify: Core Data will delete the patient but first remove the relationship. The Checkpoint will remain intact.
For the Patient entity might want either deny or cascade, depending on how you want to manage your data. Based on your usage case, you probably don't want nullify, since Checkpoints are dependent upon Patient entities.
You want nullify for the Checkpoint, since the Cascade would prevent you from deleting a checkpoint without deleting the entire patient, and Deny would effectively force the same.
Based on the scenario mentinoed, it looks like a one to many relationship between patient and checkpoint tables.
Now add a relationship from “Patient” to “Checkpoint”, and also set the inverse between the tables.
Also, set the delete rule for both relationships to “cascade”. This means that if you delete one object with Patient, the corressponding Coredata will delete the associated object as well.

Resources