Thanks for uncovering a bug. One shouldn't be able to export or import a detached entity. In future, Breeze will throw if you attempt to do either.
Now I'll discuss your issue, your aims, and what I recommend that you do.
Update master EntityManager after saving deleted entities
As I understand it you maintain a masterEm
which has only the saved state of entities. You make and save your changes in a separate editEm
. You import entities that you will change into the editEm
, make changes, save them, and (if the save is successful), you export the saved entities from editEm
and import them back into masterEm
. This is a common "sandbox editing" pattern.
Trouble arises when you delete an entity in editEm
. After save, that entity is "Detached" in the editEm
but it's still in an "Unchanged" state back in the masterEm
. How do you communicate the fact that the entity is deleted and remove it from masterEm
?
This dilemma exists independent of the "many-to-many" scenario that inspired your question.
I can see why your practice of importing the now-Detached entity from editEm
to masterEm
seemed to work. Doing that in v.1.5.3 caused the corresponding entity in masterEm
to change to the "Detached" state ... which is what you wanted. The bug, as you saw it, was that the importEntities
method didn't handle update of navigation properties properly when the imported entity is in a "Detached" state. You proposed teaching importEntities
to "do the right thing" in that scenario.
What actually happened here is that you discovered a bug. You should never have been able to export a "Detached" entity and you shouldn't have been able to import one either. Breeze should have thrown an exception when you tried to export or import a "Detached" entity.
There are all kinds of reasons why asking an EntityManager
to export/import "Detached" entities is a bad idea. I leave explication of those reasons for another day.
Rather than "solve" the problem of importing related "Detached" entities, we will throw an error.
This means that your partial solution will cease to work, leaving you apparently worse of than you are today. Fortunately, I have an alternative approach for you. I've written this utility function and tested it in DocCode:
function updateMasterWithSaveResult(masterEm, sourceEm, saveResult) {
var imports = [];
var deletes = [];
saveResult.entities.forEach(function(entity) {
if (entity.entityAspect.entityState.isDetached()) {
deletes.push(entity);
} else {
imports.push(entity);
}
});
var exported = sourceEm.exportEntities(imports, {
includeMetadata: false,
asString: false // as JSON
});
masterEm.importEntities(exported);
deletes.forEach(function(detached) {
var entity = masterEm.getEntityByKey(detached.entityAspect.getKey());
entity && entity.entityAspect.setDetached();
});
}
Updated documentation
I just added this to our "Cool Breeze" documentation almost verbatim.