在阅读了Custom EFContextProvider并实现它之后,我仍在尝试找出执行服务器端验证的最佳方法,以及如何在保存之前应用业务规则...即我的问题围绕着2应该被覆盖的方法:
protected override bool BeforeSaveEntity(EntityInfo entityInfo) { //}
protected override Dictionary<Type, List<EntityInfo>> BeforeSaveEntities(Dictionary<Type, List<EntityInfo>> saveMap) { // }
我知道文档指定“在调用BeforeSaveEntities方法之前”将为每个实体调用“ BeforeSaveEntity方法”。此外,我的问题围绕在具有域特定关系的多个实体上验证/应用业务规则,而不一定验证单个实体的属性(为此,我相信自定义验证可以作为explained here)
所以我的问题是:
由于 Z ...
答案 0 :(得分:2)
Breeze将在保存期间使用.NET验证属性执行任何已注册的验证。以下是在实体级别和属性级别应用验证属性的示例。这两个验证都将在保存任何Customer对象期间执行,并且任何验证错误都将在SaveChanges'fail'中返回。诺言。但是现在,您需要通过检查错误结果将结果错误附加到正确的实体/属性。
[AttributeUsage(AttributeTargets.Class)] // NEW
public class CustomerValidator : ValidationAttribute {
public override Boolean IsValid(Object value) {
var cust = value as Customer;
if (cust != null && cust.CompanyName.ToLower() == "xxx") {
ErrorMessage = "This customer is not valid!";
return false;
}
return true;
}
}
[AttributeUsage(AttributeTargets.Property)]
public class ContactNameValidator : ValidationAttribute {
public override Boolean IsValid(Object value) {
try {
var val = (string)value;
if (!string.IsNullOrEmpty(val) && val.StartsWith("xxx")) {
ErrorMessage = "{0} should not start with 'xxx'"";
return false;
}
return true;
} catch (Exception e) {
var x = e;
return false;
}
}
}
[MetadataType(typeof(CustomerMetaData))]
[CustomerValidator]
public partial class Customer {
[ContactNameValidator]
public string ContactName {
get;
set;
}
}
答案 1 :(得分:1)
1)通常,从服务器向客户端返回“自定义”验证错误的最简单方法是在服务器上抛出错误。我没想过但认为可能有用的是,如果您希望将该错误应用于特定实体,请创建一个包含属性的异常,该属性包含失败的实体/实体的EntityKey并抛出此异常。在客户端上,您应该能够在promise failure分支中检索此错误,并将验证错误自己应用于特定实体。 (顺便说一句,它听起来像一个合理的微风功能请求,使这个过程更容易。请发布在Breeze User Voice,以便我们可以衡量社区的兴趣。)
2)您有两种方法可以将“上下文”应用于保存。最简单的方法是通过 SaveOptions.tag 属性。此属性可以在客户端上设置,并将在服务器上反序列化,以便通过SaveOptions属性在ContextProvider中使用。 (像这样):
public class NorthwindContextProvider : EFContextProvider<NorthwindIBContext_EDMX_2012> {
protected override bool BeforeSaveEntity(EntityInfo entityInfo) {
if ((string)SaveOptions.Tag == "myCustomSaveSetting") {
}
}
另一种方法是为保存的每个“版本”创建一个完全独立的端点。您可以通过 SaveOptions 实例的“resourceName”属性执行此操作。
var so = new SaveOptions({ resourceName: "MyCustomSave" });
return myEntityManager.saveChanges(null, so);
将转到'MyCustomSave'控制器方法,而不是标准的“SaveChanges”方法。即。
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...
}
}