2016-05-27 48 views
4

比如我有兩個驗證規則驗證:如何重用數據FluentValidation

// Rule 1 
RuleFor(o => o.Email).Must((email) => this.GetDataDataFromDB(email) != 0) 
    .WithMessage("User with provided Email was not found in database!"); 

// Rule 2 
RuleFor(o => o.Email).Must((email) => this.GetDataDataFromDB(email) >= 1) 
    .WithMessage("There are multiple users with provided Email in database!"); 

正如你可以看到有兩個調用具有相同的方法的數據庫。我該如何調用它並重用其他規則的數據?

RuleFor(o => o.Email).Must((email) => this.GetDataDataFromDB(email) >= 1) 
    .WithMessage("There are multiple users with following Email '{0}' in database!", 
    (model, email) => { return email; }); 

有沒有更好的方式來顯示錯誤消息,不是所有的時間寫的lambda表達式以檢索屬性:顯示錯誤消息時

另一個問題?就像在某處保存模型一樣,然後再使用它。

簡單易用的解決方案將會很棒!

+0

RuleFor(O => o.Email)。必須((電子郵件)=> this.GetDataDataFromDB(電子郵件)<= 1)的條件<=不符合驗證消息的含義 –

回答

4

對於#1,恐怕沒有辦法做到這一點。驗證器被設計爲無狀態的,因此它們可以在線程間重用(事實上,強烈建議您將驗證器實例創建爲單例,因爲實例化起來非常昂貴.MVC集成默認執行此操作)。不要混淆靜態字段,因爲你會遇到線程問題。

(編輯:在這個特殊的簡單情況你可以結合規則到到必須在一個電話,但一般不能共享規則之間的狀態)

#2,這取決於物業你正在使用的驗證器。大多數屬性驗證器實際上允許您使用{PropertyValue}佔位符,並且該值將自動插入。但是,在這種情況下,您正在使用不支持佔位符的「必須」驗證器(PredicateValidator)。

我有其中驗證器這裏支持自定義佔位符的列表:https://github.com/JeremySkinner/FluentValidation/wiki/c.-Built-In-Validators

+0

是的,我同意@Jeremy Skinner,它可能會導致線程的一些問題。儘管我增加了一項改進。從'AbstractValidator'派生的基類以及它內部的一個getter(非靜態),如果它是private字段,它將從databse獲取數據。並且在'GetDataDataFromDB'裏面使用那個屬性。如果在'this'驗證器上下文中多次調用'GetDataDataFromDB',這將至少獲得DB數據一次。 – Edgar

1

第1部分

您想降低數據庫調用從2比1,所以你需要使用字段保存數據庫調用的結果,因爲驗證規則代碼實際「運行」工作。

Validator類:

public class MyValidator : Validator<UserAccount> 
{ 
    private int? _countOfExistingMails; 
    private string _currentEmail; 
    private object locker = new object(); 

    public MyValidator() 
    { 
     CallEmailValidations(); 
     // other rules... 
    } 
} 

這裏是郵件驗證調用單獨的方法。至於Must採取表達式作爲參數,你可以傳遞方法的名稱與它的參數:

public void CallEmailValidations() 
{ 
    RuleFor(o => o.Email).Must(x => EmailValidation(x, 0)) 
     .WithMessage("User with provided Email was not found in database!"); 

    RuleFor(o => o.Email).Must(x => EmailValidation(x, 1)) 
     .WithMessage("There are multiple users with provided Email in database!"); 
} 

和驗證方法的身體本身:

public bool EmailValidation(string email, int requiredCount) 
{ 
    var isValid = false; 

    lock(locker) 
    { 
     if (email != _currentEmail || _currentEmail == null) 
     { 
      _currentEmail = email; 
      _countOfExistingMails = (int)GetDataDataFromDB(email); 
     } 

     if (requiredCount == 0) 
     { 
      isValid = _countOfExistingMails != 0; // Rule 1 
     } 
     else if (requiredCount == 1) 
     { 
      isValid = _countOfExistingMails <= 1; // Rule 2 
     } 
    } 
    // Rule N... 

    return isValid; 
} 

UPDATE: 此代碼的工作,但更好的方法是在數據訪問層方法中實現緩存。

第2部分

在這裏被重寫規則:

RuleFor(o => o.Email).Must((email) => GetDataDataFromDB(email) >= 1) 
    .WithMessage("There are multiple users with following Email '{0}' in database!", m => m.Email) 

"C# in depth"

當lambda表達式僅需要一個單一的參數,並且 參數可以是隱式鍵入,C#3允許您省略圓括號 ,因此它現在具有此格式

陷阱:

  1. 不通過明確this以拉姆達表達式。據我所知,它可能會導致性能問題。沒有理由創建額外關閉。

  2. 我想你使用DataContextGetDataDataFromDB方法中的某種形式。所以你必須控制你的上下文的生命週期,因爲驗證器對象實例化爲singletone。