2016-04-28 83 views
12

當用戶將其更改保存在動態數據屏幕中時,我正在尋找解決方案來執行一些自定義實體驗證(這將需要數據庫訪問,跨成員驗證...)與實體框架。
驗證比我可以用屬性(它需要訪問數據庫等)更復雜使用動態數據自定義高級實體驗證

你可以攔截SaveChanges調用嗎?
我試圖覆蓋DbContext對象中的ValidateEntity,但動態數據似乎沒有調用它(可能是因爲它使用內部ObjectContext,不知道爲什麼),並且覆蓋SaveChanges也沒有幫助。
我沒有看到,我可以訂閱任何事件......

documentation應該有所幫助:

自定義驗證爲單個數據字段通過重寫 的OnValidate方法或處理驗證事件當任何數據字段被改變時被調用 。通過這種方法,您可以爲單個字段添加驗證 和業務邏輯。這種方法通常比爲單個字段添加驗證更具有通用性。當相同的驗證邏輯可以應用於多個數據字段時,這是有用的。 。它還允許您執行涉及多個字段的驗證檢查。

但我使用POCO實體框架6班,所以沒有OnValidate方法重寫,並從我讀這是LinqToSql,我找不到Validate事件他們提到。

我試圖在我的DbContext的構造函數中訂閱內部ObjectContextSavingChanges事件來手動調用ValidateEntity,但我不知道如何處理結果。如果我拋出一個DbEntityValidationException(或者,如this article建議的那樣),ASPNET就像任何異常(黃色屏幕)一樣處理它。

實現IValidatableObject也不起作用。

我也試圖實現我自己的DynamicValidator看看會發生什麼,但沒有成功,它似乎處理異常(如果我重寫ValidateException,並把一個斷點,我看到它),但它仍然向上冒泡到默認錯誤處理程序並顯示一個黃色屏幕。我肯定錯過了什麼。

那麼,如何在保存到動態數據/ EF之前對實體執行復雜驗證(交叉字段,查詢等)?

回答

0

我找到了一個解決辦法,我不喜歡,但它的工作原理:

我的上下文仍執行有效性驗證,如有必要拋出一個ValidationException

由於ListView似乎並沒有捕捉和處理異常,我做我自己的處理OnItemUpdatedOnItemInserted事件ListView的:

protected void ListView1_ItemUpdated(object sender, ListViewUpdatedEventArgs e) 
{ 
    if (e.Exception != null) 
    { 
     ValidationError.DisplayError(e.Exception.Message); 
     e.ExceptionHandled = true; 
     e.KeepInEditMode = true; 
    } 
} 

ValidationError用於將異常信息添加到驗證總結。它增加了一個「假」,總是失敗的驗證與消息。

public class ValidationError : BaseValidator 
{ 
    private ValidationError(string message) 
     : base() 
    { 
     ErrorMessage = message; 
     IsValid = false; 
    } 

    protected override bool EvaluateIsValid() 
    { 
     return false; 
    } 

    public static void DisplayError(string message, string validationGroup) 
    { 
     var currentPage = HttpContext.Current.Handler as Page; 
     currentPage.Validators.Add(new ValidationError(message) { ValidationGroup = validationGroup }); 
    } 
} 
4

我會爭辯說,像你這樣的邏輯試圖執行不屬於你的架構中的這樣一個層次。讓數據庫執行它應該達到的約束條件,如外鍵等,並讓業務邏輯在上面一層。例如,在你想要驗證的實體上,你可以添加一個IsValidForAddOrUpdate()方法,它包含了你在驗證器中放入的邏輯。然後,只需利用新方法:

if (entity.IsValidForAddOrUpdate()) 
{ 
    db.Set<Entity>().Add(entity); 
    db.SaveChanges() 
} 
else throw new DbValidationException("Entity failed validation due to rule xyz."); 
+0

我同意這個說法,我也相信業務邏輯不應該與實體框架耦合 – Eldho

+1

這是有爭議的。也許一個領域層對象可以有驗證。只要在EF前面沒有使用可怕的'儲存庫層'模式... – James

+0

我同意,但動態數據並沒有提供很多驗證選項。但問題不在於,問題在於DynamicValidator沒有捕獲到DbValidationException(儘管我發現文檔和文章說它應該),所以我得到一個黃色的屏幕。 現在我甚至沒有試圖建立一個良好的架構,只是爲了有一些工作:(。 –

3

一種方法如何實現這一目標可以實現你的實體IDataErrorInfo界面是這樣的:

public partial class MyEntity : IDataErrorInfo 
{ 
    public MyEntity() 
    { 
    } 

    ... 

    #region IDataErrorInfo Members 
    public string Error 
    { 
     get { throw new NotImplementedException(); } 
    } 
    public string this[string propertyName] 
    { 
     get 
     { 
      //Custom Validation logic 
      return MyValidator.ValidateProperty(this, propertyName); 
     } 
    } 
    #endregion 
} 

要訪問IDataErrorInfo的方法,當前的DbContext可以使用this answer。 然後覆蓋您的上下文的SaveChanges方法:

public override int SaveChanges() 
    { 
     this.ObjectContext.DetectChanges(); 

     // Get all the new and updated objects 
     var objectsToValidate = 
     ChangeTracker.Entries().Where(x => x.State == EntityState.Modified || x.State == EntityState.Added). 
     Select(e => e.Entity); 

     // Check each object for errors 
     foreach (var obj in objectsToValidate) 
     { 
      if (obj is IDataErrorInfo) 
      { 
       // Check each property 
       foreach (var property in obj.GetType().GetProperties()) 
       { 
        var columnError = (obj as IDataErrorInfo)[property.Name]; 
        if (columnError != null) { 
        //Handle your validation errors 
        throw new DbEntityValidationException(columnError); } 
       } 
      } 
     } 

     return base.SaveChanges(); 
    } 

又見this answer,使其與DataAnnotations工作。

您寫道:

如果我把一個DbEntityValidationException(或ValidationException 喜歡這篇文章中所建議的),ASPNET處理它像任何異常 (黃屏)。

請參閱this answer。當你打電話給SaveChanges時,你需要捕獲DbEntityValidationException(或ValidationException),如果你沒有在控制器中捕獲它們來處理它們,它們將被默認的錯誤處理程序處理。

或者您可以使用DynamicValidator控制趕上ValidationExceptions:

<!-- Capture validation exceptions --> 
    <asp:DynamicValidator ID="ValidatorID" ControlToValidate="GridView1" 
     runat="server" /> 

DynamicValidator的問題是,它需要ControlToValidate屬性,並將其捕獲只能從控制未來例外。其他異常中封裝的異常也會產生問題。有一種解決方法 - 您可以繼承DynamicValidator並覆蓋其ValidateException方法see this blog

參見this article

+0

是的,正是我發現的,但DynamicValidator沒有捕獲異常,我不知道爲什麼。我調試了一下,我發現它進入了ValidateException方法,它似乎檢測到它並對它進行處理([源代碼](http://referencesource.microsoft.com/#System.Web.DynamicData/DynamicData/DynamicValidator)。 cs,a9f61764351be893,references)),但是異常仍然會出現在默認的錯誤處理程序中 我甚至從Dynamic Data Futures軟件包中嘗試了ImprovedDynamicValidator,但它也不起作用 我無法在控制器,因爲沒有動態數據 –

+0

我明白了,有趣的問題,如果它在週四沒有得到迴應,我會在週四看看它。 –