Search code examples
breezeabortsavechanges

breezejs cancel saveChanges due to validation failure in BeforeSaveEntity


I created my own ContextProvider, sub classed from EFContextProvider. In BeforeSaveEntity I am running some business logic to validate the transaction. I need the updates to be "all or nothing", so if the 3rd entity in the collection fails the validation, the entire batch should be discarded, even though Ive already returned "true" for the first 2 entities.

I have a class level property thats getting set when any entity fails. In the final check in BeforeSaveEntities I can get the value of the flag.

I think this is where I can abort the update, but not sure how. Do I clear the map? Or throw an error?

Also, I will need to re-query the DB for my validation routines. I've read some posts that talk about creating a 2nd instance of the context to do the querying for the current values. Is there some docs on doing this, or gotchas I need to be aware of?

thanks


Solution

  • In your BeforeSaveEntities call you can throw an EntityErrorsException: Here is an example where we throw an exception if there is attempt to save any "Order" objects within a save bundle:

    [HttpPost]
    public SaveResult SaveWithEntityErrorsException(JObject saveBundle) {
      ContextProvider.BeforeSaveEntitiesDelegate = ThrowEntityErrorsException;
      return ContextProvider.SaveChanges(saveBundle);
    }
    
    private Dictionary<Type, List<EntityInfo>> ThrowEntityErrorsException(Dictionary<Type, List<EntityInfo>> saveMap) {
      List<EntityInfo> orderInfos;
      if (saveMap.TryGetValue(typeof(Order), out orderInfos)) {
        var errors = orderInfos.Select(oi => {
          return new EntityError() {
            EntityTypeName = typeof(Order).FullName,
            ErrorMessage = "Cannot save orders with this save method",
            ErrorName = "WrongMethod",
            KeyValues = new object[] { ((Order) oi.Entity).OrderID },
            PropertyName = "OrderID"
          };
       return new EFEntityError(oi, "WrongMethod", "Cannot save orders with this save method", "OrderID");
        });
        var ex =  new EntityErrorsException("test of custom exception message", errors);
        // if you want to see a different error status code use this.
        // ex.StatusCode = HttpStatusCode.Conflict; // Conflict = 409 ; default is Forbidden (403).
        throw ex;
      }
      return saveMap;
    }
    

    And you should use BeforeSaveEntities exclusively instead of BeforeSaveEntity as your save logic becomes more complicated.