After reading about Custom EFContextProvider and implementing it, I am still trying to figure out what is the best way to perform server side validation and how to apply business rule before saving...Namely my questions are revolving around 2 methods that are supposed to be overridden:
protected override bool BeforeSaveEntity(EntityInfo entityInfo) { //}
protected override Dictionary<Type, List<EntityInfo>> BeforeSaveEntities(Dictionary<Type, List<EntityInfo>> saveMap) { // }
I am aware that docs specify that "BeforeSaveEntity method will be called for every entity before the BeforeSaveEntities method is called" once. Also, the questions I have revolve around validating/applying business rules on multiple entities that have domain specific relationships and not necessarily validating single entity's property (for that, I believe custom validation could work as explained here)
So my questions are:
Thanks Z...
1) Typically the simplest way to return 'custom' validation errors from the server to the client is to simply throw an error on the server. What I have not tried but think might work is that if you want that error to be applied to a specific entity, create an exception that includes a property that contains the EntityKey's of the entity/entities that fail and throw this exception. On the client you should be able to retrieve this error, in the promise failure branch, and apply the validation error yourself to the specific entity. ( By the way, it does sound like a reasonable feature request for breeze to make this process easier. Please post it on the Breeze User Voice so we can gauge the community's interest.)
2) You have two methods to apply a 'context' to a save. The simplest is via the SaveOptions.tag property. This property can be set on the client and will be deserialized on the server for use within your ContextProvider via the SaveOptions property. (something like this):
public class NorthwindContextProvider : EFContextProvider<NorthwindIBContext_EDMX_2012> {
protected override bool BeforeSaveEntity(EntityInfo entityInfo) {
if ((string)SaveOptions.Tag == "myCustomSaveSetting") {
}
}
The other approach is to create a completely separate endpoint for each 'version' of your save. You can do this via the 'resourceName' property of the SaveOptions instance.
var so = new SaveOptions({ resourceName: "MyCustomSave" });
return myEntityManager.saveChanges(null, so);
will go to the 'MyCustomSave' controller method instead of the standard "SaveChanges" method. i.e.
public class NorthwindIBModelController : ApiController {
[HttpPost]
public SaveResult MyCustomSave(JObject saveBundle) {
ContextProvider.BeforeSaveEntitiesDelegate = MyCustomBeforeSaveEntities;
return ContextProvider.SaveChanges(saveBundle);
}
private Dictionary<Type, List<EntityInfo>> MyCustomBeforeSaveEntities(Dictionary<Type, List<EntityInfo>> saveMap) {
// your code...
}
}