Am having few doubts with parent child context set-up and how the data behaves. Can anyone please suggest a link where i can find proper explanation on how they work.
Few Points & Observation
Parent context acts as store for child context :- But the changes in the parent are not reflected in the child.
Question 1: If parent context acts as store for child context then why does the changes in the parent are not reflected in the child context, while the child fetches them.
Observations :
Insert in parent :- Child fetch requests get those objects.
Update/delete a object in parent :- Then the fetch request do not get the updated object instead it provides us with the object in child context, so if we need the updated object we have to either reset the context but then we will lose all the changes in the child context or refresh the object.
Question 2: Child overwrites parent context values. So if the user has modified something in parent context and child has also modified the same thing then the updates of user will be lost. This is not much problem until relationships are involved.
Say there is one to many relationship between entity A,B (A->>B).
Parent Context : Inserts a new child to entity A say Child-1.
Child Context : Deletes both entity A and all its child.
So now when the child saves to parent context, then it deletes entity A and its old child, the newly inserted child-1 remains in the context with null referencing parent.
How can i resolve this issue?
Question 1
Because you have already fetched the data, if you want to force a fetch as you said you should either reset the context or refresh the object.
Question 2
You can try to use cascade delete if you want to always delete entities B when the parent entity A is deleted.
Related
Am using a parent-child context syncing data with cloud kit. Am facing a problem of child overwriting the parent data. I know this is how it works but is there anything that can be done.
Below is the exact scenario.
Model
Parent Entity : A
Child Entity : B
A->>B is one to many relationship.
Context:
Parent Context (MOC) :- Used for CRUD operation by users.
Child MOC (CMOC) :- Used for syncing data from cloud kit.
Senario:
A parent is deleted from child context
A child for that parent is inserted on parent context.
If the save of child occurs, it overwrite the parent moc while leaving the newly inserted child without a parent.
So this leaves a child which don't have any reference parent.
When parent is deleted from child context, it will also be deleted from the parent context when save is performed. Changes from child contexts are propagated to parent context. This is by design.
What are you trying to accomplish? There may be another way.
How are conflicts resolved when a child NSManagedObjectContext is saved and the changes are pushed to the parent NSManagedObjectContext?
For instance, lets say you are updating NSManagedObject Person by setting the attribute age to 18 on a child context with an NSPrivateQueueConcurrencyType from data from a server. At the same time, the same NSManagedObject Person age attribute is updated to a value of 20 by the user on the parent NSManagedObjectContext with NSMainQueueConcurrencyType.
After both updates a save is called on the child context which propagates to the parent NSManagedObjectContext.
What is the value of age at this point? Does the child NSManagedObjectContext overwrite the parent NSManagedObjectContext? Do NSMergePolicies apply here?
There is no conflict resolution when saving from a child to a parent. The child always changes the parent, regardless of what values the parent has, or whether the parent has unsaved changes itself.
Furthermore, there is no merge policy or built-in other way to alter this behavior.
It is possible to write your own merge policy management, but it's a bit tricky. You are probably better off just knowing the rules.
I am also interested in understating how iOS 5+ parent contexts work. I am using RestKit 0.2x but I think these are general Core Data questions.
Let's say we have this store coordinator/contexts hierarchy:
Persistent Store Coordinator (PSC) -> PS Managed Object Context (PS-MOC) -> Main Queue MOC (MQ-MOC).
For a request RestKit creates a temporary Private Context (P-MOC) from MQ-MOC and on success by default saves the changes back all the way to the PSC:
PSC -> PS-MOC -> MQ-MOC [-> P-MOC]
I also manually create managed objects and modify properties directly on the MQ-MOC.
My questions:
Are my unsaved MQ-MOC changes passed to child P-MOQ when created?
Should I save my MQ-MOC changes before a child P-MOQ gets created? Should I save these changes all the way to the PSC?
If P-MOQ is configured to save only to its parent MQ-MOC context, the newly introduced changes look like my MQ-MOC unsaved changes?
Are my unsaved MQ-MOC changes passed to (an existing) child P-MOQ?
Unsaved, never. Saved, no, because they aren't required there so RestKit doesn't check and merge the changes.
How about unsaved changes when the child P-MOQ is created?
Anything saved in the parent when the child is created will be available in the child.
Should I save my MQ-MOC changes before a child P-MOQ gets created?
If the child needs them, yes (though in theory RestKit should detect that an object you use in a request isn't saved and save it for you, best not to rely on that).
Should I save these changes all the way to the PSC?
Yes. Having things saved but not persisted will just lead to issues in the future.
If P-MOQ is configured to save only to its parent MQ-MOC context, the newly introduced changes look like my MQ-MOC unsaved changes?
A child will push changes up to its direct parent but no further, so in effect, yes.
Just to check, you should be aware of the RestKit added method saveToPersistentStore:.
Let's say I have a class Parent that has a one-to-many relation with a target class Child. Both Parent and Child objects are not user created, I am creating this objects in Data Browser and I don't know how to set a relationship or a pointer on a Child back to it's particular Parent. I can get Child objects of a Parent with no problem. But, how can I get the Parent of a Child? I don't want to keep passing both Parent and Child objects from VC to VC. Once again both objects are NOT user created so I can't do:
[Parent setObject:Child forKey:"child"];
and then query Parent class like this:
[query whereKey:#"child" isEqualTo:Child];
Also querying all Parents and their relations and then getting that particular Child and then going back to the Parent seem to be an overkill.
So, how can I set the particular Parent on a Child object in Data Browser to point back to the parent? And how to get that Parent object from the code if I want to use only Child object?
This is a case of where using a reverse pointer might be more useful. This can be done in addition to your existing relationship if you want, but requires some fancier save logic.
Simply add a parent column to Child that is of type Pointer<Parent>.
To get all children of a parent you just do a query:
[childQuery whereKey:#"parent" isEqualTo:parent];
To query a child and also get the parent:
[childQuery includeKey:#"parent"];
// filter as needed
In the block that looks are children you can just use:
PFObject *parent = child[#"parent"];
It will be a fully populated Parent due to the includeKey:.
NOTE: if you keep both relationships, creating new objects gets trickier as you'll have to save the parent/child (with child.parent unset) then update the child to point to the parent and save it again.
When I create a new entity and set its navigation property and then reject the changes the parent holds onto a blank entity. Do I need to explicitly remove the new entity from the parent before rejecting changes? I did not explicitly add it to the parent I just set the new entity's parent id.
Rejecting changes on a new entity simply discards the entity - making its entityState 'detached'. Any children that were attached to the parent effectively get stranded in this case, i.e. they have no parent.
In other words, Breeze does NOT call rejectChanges on any children as a result of a rejectChanges on a parent. This is deliberate.
So your best bet is to call rejectChanges on the children as well. If they were new entities themselves they will also become detached, otherwise their parents will revert to whichever entity was their previous parent.
Note that you can use the EntityManager.getEntities method to return all of the entities of specified entityTypes and entityStates. This can be useful in determining which entities you want to 'roll back'.
See the Entity Manager getEntities method