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.
Related
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.
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.
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:.
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
It seems the new queue based MOC together with nested MOC introduced in iOS 5 serve as an simpler and cleaner concurrency model, so I'm happily using it now. But there are several things that are not clear to me:
Do child MOCs pulls parent MOC's changes automatically? Or do I still need to coordinate them manually? If the latter, how to manually refresh the children to incorporate parent changes?
(I know how things work the other way around -- parent MOC gets changes from a child MOC when the child saves.)
What will happen on saving a child MOC if there are conflicts between changes in the child and changes in parent? Is mergePolicy also responsible for resolving conflicts between child MOC and parent MOC?
Yes and no, depending on your definition of "pulls parentMOCs changes automatically." If you mean, the next time a child fetches, it will get the updated data, then yes. If you mean will objects automatically get changed, then no. The reason is that a MOC is a scratchpad, and it will not change without you changing it.
Yes, you will have to resolve merge conflicts if you are making changes to the same objects/relationships from multiple places. This is a complex issue, and can not be sufficiently answered in a SO answer. You should really read the Core Data Programming Guide, especially the section on Change Management.
EDIT
Say I'm holding object A in child MOC and add a relationship B to A in parent MOC. What do I get if I access A.B? nil? What should I do if
I want to see A.B in child MOC? Use refreshObject:mergeChanges: to
refresh A, or use objectWithID: to fetch A again? Is there any way to
refresh the whole child MOC? I have a very complex object network in
child MOC and I don't want to(or just can't) refresh/re-fetch every
object one by one.
When looking at object A through the child MOC, you will NOT see the change in the parent MOC until you refetch from the child MOC. If you want to see what's in the parent, you can do so via another fetch on the MOC, or through any of the methods to get a apecific object from the store. However, I must stress that you need to read the documentation about each fetch, because they may have side effects. The exact answer depends on which approach you choose.
Typically, if you are doing continual change, you want to either make changes in a child, and push them to the parent, or handle the DidChange notification to make the changes seem "automatic."
Does mergePolicy work here?
Yes.
Again, the best answer I can give you here on SO is to point you to the "Core Data Programming Guide." Pay special attention to these two sections:
https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/CoreData/Articles/cdFetching.html#//apple_ref/doc/uid/TP40002484-SW1
https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/CoreData/Articles/cdChangeManagement.html#//apple_ref/doc/uid/TP30001201-CJBDBHCB