I maintain a Breeze ASP.NET Web API that was initially written about 10 years ago. I didn't write it and I'm not an expert in Breeze. The client is a cellphone app developed by a third party. This replaced a previous incarnation of the app that was developed in-house contemporaneously with the API.
I have recently discovered that both versions of the client on occasions call SaveChanges
multiple times with the same data. This has resulted in duplicate data in the database. I can reproduce this, but not in a consistent way. It seems a bit random.
In time, we'll get the third party involved in this, but that isn't going to happen soon. So, I want to change the server to stop the duplication. By inspecting the saveBundle I can determine whether a save of the entity instance within is already in progress. The question is, what should the contents of the SaveResult
be when I've stopped a duplicate call? I don't want to trigger any client behaviour. I want it to ignore the SaveResult
. I don't want the user to be bothered by an error message.
The most "Breeze" way to do this would be to attach a BeforeSaveEntities delegate that would check for dups by looking at the save bundle. If it is a duplicate save, the delegate would return an empty save bundle so that there is nothing to save.
[HttpPost]
public SaveResult SaveChanges(JObject saveBundle)
{
ContextProvider.BeforeSaveEntitiesDelegate = IgnoreDupSaves;
return ContextProvider.SaveChanges(saveBundle);
}
private Dictionary<Type, List<EntityInfo>> IgnoreDupSaves(Dictionary<Type, List<EntityInfo>> saveMap)
{
if (IsDuplicateSave(saveMap)) // you implement IsDuplicateSave method
{
return new Dictionary<Type, List<EntityInfo>>();
}
return saveMap;
}
The Breeze client should prevent the duplicate saves in the first place. It normally doesn't allow a save if one is already in progress, but this behavior can be overridden to allow parallel saves.