When you mark an entity as deleted it marks its children as well, is there a way to only mark the parent deleted? - breeze

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.

Related

Breeze entityManager importEntities duplicating updated child entities

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.

Grails one to many relationship behavior

I know that one of the benefits of the one to many relationships is cascading behavior such as the deletion of a parent(owning) object resulting in
the deletion of the children(objects the parent owned) but what if the objects owned by it are also owned by another parent do they still get deleted if only one parent gets deleted?
GORM/Grails is smart enough to figure out in this case that the child instances should not be deleted when they are in use by another instance. (As indicated in my comments to the original question)

breeze: behavior of setDeleted

I have a grid which shows a list of entities.
Each row has a delete button.
Once the user clicked on the delete button for a given entity I want to change the css of the row and to replace the delete button with a cancel button.
So on the delete button event handler, I do :
myEntity.entityAspect.setDeleted();
But as soon as I do that, the entity is removed from the collection and the row disappear from the grid.
Is there a way to prevent that ? I just want to mark the entity as 'deleted', and postpone any change until user clicks on save button.
The only alternative I see, is to add a property isDeleted to my client-side model and to base my logic on that. But it means I have to handle change tracking myself and loop through the entities on save to call setDeleted for entities which isDeleted property is true. I'm not fond of this solution. Is there something better I'm missing with breeze ?
My guess is that your collection is the value of one of Breeze's navigation properties. These collections are 'live' in that if you delete an entity, the entity becomes removed from all live collections to which it belongs.
So the best answer would be to copy the entities into your own collection and bind to that. Your own collection will not be 'live' and deleting entities will not remove them from the collection.
The problem with 1) is that when you delete an entity we need to sever its relationships with any other entities. This really is the essence of deleting, we want the environment to look like it will after the delete is committed ( via EntityManager.saveChanges())
When you say that you do not want the navigation properties to be set to null after a delete I am assuming that you are talking about a scalar (1->1) or (n->1) navigation. (nonscalar navigations simply remove the entity from the collection) The first issue is whether you are talking about navigations 'To' the deleted entity or 'From' the deleted entity. In the case of 'NOT" removing the navigation 'to' a deleted entity we would be causing many if not most existing breeze apps to fail. Most apps expect to see entities disappear when you delete them.
In the case of 'NOT' removing the navigation 'from' a deleted entity, the concept make more sense except that you cause two more issues. The first is that this breaks any 'bidirectional' navigations, i.e. you can no longer roundtrip between the 'from' and 'to' navigations. But more importantly, we view a 'delete' as a precursor to an eventual 'detach' operation ( which will occur after a successful save). The primary value of the 'detach' is that it recovers memory because we have effectively removed any references to the 'deleted' object, which means that it can be garbage collected. If we leave any navigation properties intact this garbage collection will never occur, and we end up with a memory leak.
We could get around this by having the 'detach' operation also remove navigation properties but the rules begin to get harder to explain.
If you still feel strongly about this, please post your suggestion to the Breeze User Voice. If we see some substantial interest in this, we will try to come up with a solution, but right now we don't have a good answer to this that doesn't add real conceptual complexity. (Something we really try to avoid).
Can you give more detail about the 'validations' that you are seeing? Are these validations on the 'deleted' entity or on the still alive entities that were pointing to the deleted entity? Not having the first occur makes a lot of sense (and we should fix it if this is the case), not having the second occur does not make sense because you really are causing a real validation failure.
Ok, I have tried Jay's solution. First I do a deep copy using lodash.js:
$scope.sourceMaterials = _.clone($scope.request.sourceMaterials, true);
then I bind my grid to $scope.sourceMaterials. User clicks on delete button for a given row and I do:
var document = $scope.sourceMaterials[index];
document.entityAspect.setDeleted();
The problem is that breeze sets to null all the navigation properties of my entity (see removeFromRelationsCore function in breeze.js).
Doing so affects the values shown on screen to the user. For instance one of the required field gets nulled by breeze. So when user clicks on the save button, the validation fails.
To sum up I have two issues:
navigation properties should not be set to null when deleting my entity
the validation should not be triggered for an entity that has its state set to deleted
Could you shed some light on this please ?
EDIT
Following Jay's answer, I can confirm that:
1) navigation property is nulled FROM the deleted entity and I'd like that to be prevented somehow
ex: I have an entity Document with a 1 -> 1 np named DocumentType. If I set deleted on Document, then DocumentType is nulled.
2) validation rules occur on properties of the deleted Entity (those that were nulled)
which one of these problems should I report on user voice ?

IOS Core Data Cascade Delete Issues

I found a question very similar to mine here, but it was un-replied to and unanswered so I will try again.
I may be missing something in regards to cascade deletes and core data. I am used to cascade deletes working as designed in RDBMS apps but having issues with core data.
I have an object record that get's inserted into entity via an "add form" called modally from a table view. No problem.
In another session I will insert objects into a related details entity (many) where there is a common loadID attribute in both. No problem.
In another session, I will call up the original table view to view the parent "loads", and swipe-delete, save the context, and the parent load gets deleted from the one side entity. No problem, (except apparently details objects in a many side entity do not get removed)
When I open the sqlite data source with a db manager, I see the child records (pay detail items) are being orphaned. I have double and triple checked the cascade delete settings in the relationships. Have tried different entity relationship settings combinations, but nothing seems to get the many records to automatically delete along with the parent record.
If you can't define corresponding keys in core data, how does core data know what belongs to what when you operate in multiple sessions (contexts) adding child objects to the many-side entity?
I don't know if I'm doing something wrong or missing a vital step prior to inserting new child objects in the many table, or doing something wrong or missing a step when deleting the parent object.
But I would suggest all with cascade deletes set to open your data file and be sure there are not orphaned objects (records)

Replace entities in to-many relationship in Core Data

When I retrieve an entity from the one side of a one-to many relationship, I create a mutable array from the set that is the collection of entities from the relationship. I manipulate, edit or otherwise change those entities, possibly delete existing or add new.
When through with the changes I simply use the array to create a new set then replace the original set with that which I created like so:
self.myOneSideEntity.theManySideEntitiesRelationship = [NSSet setWithArray:myNewArrayOfEntities];
It occurred to me that replacing the set may not be deleting the old members. What happened to them? Is this the proper way to edit the collection of related objects? Am I leaving any kind of orphans or going against best practices with this technique?
My relationship is set up with an inverse, cascade delete on the one side, nullify on the many side and the inverse relationship is not optional.
I've spent some days to understand similar behavior in my application.
Relation's "Delete Rule" works only when the object that contains relation is deleted itself. If you simply replace one set of objects with another (as you do) - nothing happens. Child objects that were in old set will simply have inverse relations set to nil. So if that relation (from child side) is not optional, you will get CoreData error when saving context.
For now I didn't find any way to manage this, except manual deletion of old objects.
For me the issue was with getting objects which were wired with current object. (groupObject.docs)
It was solved when I add context by which I get this data.
I'm using MagicalRecord:
[GroupObject MR_findAllInContext:[NSManagedObjectContext MR_defaultContext]]
instead of
[GroupObject MR_findAll]

Resources