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
Related
When you mark an entity as deleted by setting the entityAspect it marks its children as deleted as well. Is there a way to only mark the parent deleted? Or a way to go through and mark the children as unchanged after the fact?
You don't want to mess with the navigation properties - I will tell you that straight away. My suggestion is to model your question as if you had to ask it using T-SQL.
In T-SQL, can you delete a parent record, but leave the children? No. I mean you could, but why? You just created orphaned child records in the database. Are you going to delete the foreign key but leave the data? What a mess.
The only reason you are able to map a parent child relationship in Breeze is because of the navigation properties that were created based on the parent / child relationships defined in the database. If you can't do it in the database, you can't do it in Breeze.
If the model refuses to budge and you decide to go forward with this anyway, you need to return data that is not linked via relationships. You can create a view for the parent and children... but you will need to manually manage the load. If your entities are based on a view, they probably are not going to be updatable.
Sorry, no code to post. I gave up on this a long time ago.
Breeze does not mark child entities as deleted if you delete the parent. We haven't implemented cascading deletes in Breeze. You must have code in your application that is doing this. Breeze disconnects the child entities from the deleted parent by clearing the foreign key properties, so the child entities will be in modified state. However, you won't be able to successfully save w/o violating FK constraints in your DB. You either have to implement cascading deletes on the server or manually delete the child entities.
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.
I am trying to use the "sandbox editor" approach with exportEntities and importEntities as detailed in the Cool Breezes section (and in many SO posts).
I have a main/parent entity which has one or more child entities. I have an HTML view (using Aurelia but that doesn't matter) that displays the 4 properties from the parent entity and then 3 or 4 properties from each of the child entities. In this example the parent has just one child entity.
The view uses a new entityManager and the parent/child entities have been imported from the 'master' entityManager in the usual export/import way. So far so good.
I edit one of the properties on the child entity and save it. I pass the saveResult to a copy of the updateMasterWithSaveResult. Everything works fine up to the line masterEm.importEntities(exported);
imports[] contains just one updated child entity - correct.
deletes[] is empty - correct.
exported contains the updated child entity info - correct.
masterEm contains the original parent and the original (non-updated) child - correct.
The problem
After it has called masterEm.importEntities(exported), masterEm now contains the original parent BUT the child property array now has 2 elements in it and both of them are the same, updated, child element. They are identical - same key, same everything.
Analysis
After much tracing I've narrowed this down to _linkRelatedEntities in a50_entityManager.js. At the bottom of this function it handles the foreign keys of the child and calls parent.getProperty(invNp.name).push(entity) or parent.getProperty(invNp.name)._push(entity) but
doesn't appear to check if the child is already connected. So in this case the child entity is
already in the array but gets added a second time.
Question: Is this the expected outcome? And, if so, am I missing something or is there a 'proper' way around it so that I end up with only one child element?
My temporary solution is to run a de-duplication on the child array after running importEntities but that seems hacky to say the least.
I have a simple Core Data app that has a many to many relationship from entity A to B. I have kept the delete rule as nullify.
I simply want that when all entities of type A that relate to an entity of type B are deleted. In other words, when all relationships from a given B to A are nil, that particularly object of entity B should be deleted.
Now I noticed that, at least for me, this isn't happening automatically. Do I have to manually check to see if a given B object has all relationship to A as nil and then delete them manually or is there an automatic way to achieve it?
In your NSManagedObject subclass
- (void)willSave
{
// Check for relationship and delete self if empty
}
...or is there an automatic way to have this happen?
Yes if you let Core Data to manage this.
If you have two entites, say Parent and Child where the former has a one-to-many relationships with the latter
you can set the children relationship with a Delete Rule Cascade.
On the contrary, the parent relationship would be
The check on the optional flag depends on if a Child could exist with or without a Parent associated with it.
Here the delete rules mean the following.
If I delete a parent, all the children will be deleted. If I delete a child, nothing would happen on the parent (in other words the parent won't be deleted).
The inverse relatioship between the Child and the Parent is very important since lets Core Data to maintain the graph consistency. So, you should (a must for me) use it in every model you have.
Is this what you want to achieve? Let me know if you need something else.
Update 1
Only children can be deleted and not the parent. And I want that when
all children of a given parent are deleted, the parent object should
be removed from the store as well. the parent cannot be directly
deleted.
Deleting a parent it's up to you. In your code you will just not delete a parent if you want. I would use the configuration I provided since, if you delete a child, the parent will remove the reference to it.
To delete all the children that belong to a specific parent I would use a simple fetch request against Child where the predicate would be
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"parent == %#", parentOfTheChildrenYouWantToDelete];
Once run, the request will return a NSArray of managed objects. for in to delete them.
In my understanding of your question, I recommend you look into running a specific fetch at a certain point in your code to check for nil against the relationship, and then delete manually.
So to answer your question, my understanding is that there is no "automatic" mechanism.
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.