asp.net-web-apientity-framework-6breeze.net-4.8

How to ignore duplicate Breeze SaveChanges calls


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.


Solution

  • 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.