Search code examples
breezeseparation-of-concernssavechanges

overriding breeze BeforeSaveEntity()


I was having the exact same problem as discussed in breezejs issues with the save bundle and the answer explains it great.

The problem I have is - my application is somewhat large, having about 20+ entities that we modify. Hence if I override the BeforeSaveEntity() within my datacontext and add all the business logic there it would be very cumbersome. We do have a clear separation of concerns as I have mentioned in the following question (mind the half-completed title): Is it a good practice to use multuple

So is there anyway I can do this in a more organized manner? I mean handling the BeforeSaveEntity for related entities in one single repository and likewise?


Solution

  • Of course you can branch inside your BeforeSaveEntities method, as shown in the code of the answer you linked to above. Inside each if block, you could instantiate a helper class or repository to handle each entity type.

    A more domain-based approach would be to have multiple subclasses of EFContextProvider<MyDbContext>. Each one would have its own BeforeSaveEntities method to handle its own domain business rules:

    public class AccountManagementContextProvider : EFContextProvider<MyDbContext>
    {
        Type[] allowedTypes = new Type[] { typeof(Account), typeof(AccountAddress) };
    
        protected override Dictionary<Type, List<EntityInfo>> BeforeSaveEntities(Dictionary<Type, List<EntityInfo>> saveMap)
        {
            var illegalTypes = saveMap.Keys.Except(allowedTypes);
            if (illegalTypes.Any())
            {
                throw new ArgumentException("Attempt to save illegal entities");
            }
    
            // account management stuff...
        }
    }
    
    // in a separate file...
    public class InventoryContextProvider : EFContextProvider<MyDbContext>
    {
        protected override Dictionary<Type, List<EntityInfo>> BeforeSaveEntities(Dictionary<Type, List<EntityInfo>> saveMap)
        {
            // inventory stuff...
        }
    }        
    // etc.
    

    You can instantiate the appropriate ContextProvider instance in your controller methods:

    [HttpPost]
    public SaveResult SaveAccount(JObject saveBundle)
    {
        var context = new AccountManagementContextProvider();
        return context.SaveChanges(saveBundle);
    }
    
    [HttpPost]
    public SaveResult SaveInventory(JObject saveBundle)
    {
        var context = new InventoryContextProvider();
        return context.SaveChanges(saveBundle);
    }
    

    ... which you call from the client using named saves:

        var saveOptions = new breeze.SaveOptions({ resourceName: 'SaveInventory' });
        return manager.saveChanges(null, saveOptions);