2

在阅读了自定义 EFContextProvider并实现它之后,我仍然试图找出执行服务器端验证的最佳方法以及如何在保存之前应用业务规则......也就是说,我的问题围绕着 2 种方法应该是被覆盖:

  • protected override bool BeforeSaveEntity(EntityInfo entityInfo) { //}
  • protected override Dictionary<Type, List<EntityInfo>> BeforeSaveEntities(Dictionary<Type, List<EntityInfo>> saveMap) { // }

我知道文档指定“在调用 BeforeSaveEntities 方法之前,将为每个实体调用 BeforeSaveEntity 方法”一次。此外,我的问题围绕在具有特定领域关系的多个实体上验证/应用业务规则而不必验证单个实体的属性(为此,我相信自定义验证可以按照此处的说明工作)

所以我的问题是:

  1. 如何从服务器返回验证错误?一旦我应用了业务规则,如果它们失败了,我如何向一个或多个实体添加验证错误?
  2. 如何传递某种验证上下文,以便服务器端代码“知道”要应用哪些业务规则?我的应用程序可以在几个不同的地方添加新客户,并且根据应用程序上下文,应该应用业务规则或者它应该是可选的。例如,如果有明确的“添加新客户”屏幕和“打印检查”屏幕,允许“即时”创建新客户(在这种情况下,必须检查更多规则)。这可能不是理想的设计,但它是必需的。很少有其他地方也可以创建客户......虽然在服务器端,我没有得到这个“上下文”来决定如何应用(以及以何种顺序)业务规则......此外,

谢谢Z...

4

2 回答 2

2

Breeze 将在保存期间使用 .NET Validation 属性执行任何已注册的验证。下面是在实体级别和属性级别应用验证属性的示例。这两个验证都将在保存任何 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;
  }
}
于 2013-06-05T17:22:52.417 回答
1

1) 通常,从服务器向客户端返回“自定义”验证错误的最简单方法是在服务器上简单地抛出一个错误。我没有尝试但认为可能有效的是,如果您希望将该错误应用于特定实体,请创建一个异常,其中包含一个属性,该属性包含失败并抛出此异常的实体/实体的 EntityKey。在客户端上,您应该能够在承诺失败分支中检索此错误,并将验证错误自己应用于特定实体。(顺便说一句,对于让这个过程更容易的微风,这听起来确实是一个合理的功能请求。请将它发布在微风用户语音上,以便我们评估社区的兴趣。)

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”方法。IE

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...
    }
 }
于 2013-06-05T00:11:44.230 回答