雖然 UI 層常做前端驗證,但模型層驗證是最後一道防線,確保資料完整性不因介面繞過。ActiveRecord 內建 ActiveRecordValidationBase 提供聲明式驗證,零配置整合 NHibernate 攔截器。
| 屬性 | 用途 | 範例 |
|---|---|---|
[ValidateNotEmpty] | 不可為空字串或 Null | [Property, ValidateNotEmpty] public string Name |
[ValidateEmail] | Email 格式驗證 | [Property, ValidateEmail] public string Email |
[ValidateRegExp] | 正則表達式驗證 | [Property, ValidateRegExp(@"\d{6}")] public string ZipCode |
[ValidateIsUnique] | 資料庫唯一性檢查 | [Property, ValidateIsUnique] public string UserName |
[ValidateConfirmation] | 兩欄位值一致(如密碼確認) | [Property, ValidateConfirmation("Password")] public string ConfirmPassword |
public class Custom : ActiveRecordValidationBaseif (entity.IsValid()) { ... } else { var errors = entity.ValidationErrorMessages; }[ActiveRecord("Customs")]
public class Custom : ActiveRecordValidationBase {
[PrimaryKey(PrimaryKeyType.Native)]
public int ID { get; set; }
[Property, ValidateNotEmpty]
public string Name { get; set; }
[Property, ValidateEmail]
public string Email { get; set; }
[Property, ValidateRegExp(@"\d{6}")]
public string Post { get; set; }
[Property, ValidateRegExp(@"(\(\d{3,4}\)|\d{3,4}-)?\d{8}")]
public string Phone { get; set; }
}
[Test]
public void TestAllValidation() {
var custom = new Custom {
Name = "Terry Lee",
Email = "lhj_cauc@hotmail.com",
Phone = "022-24096335",
Post = "300192"
};
Assert.IsTrue(custom.IsValid());
Assert.AreEqual(0, custom.ValidationErrorMessages.Length);
}
[Test]
public void TestPostValidation() {
var custom = new Custom {
Name = "Terry Lee",
Email = "invalid#mail.com",
Post = "222t"
};
Assert.IsFalse(custom.IsValid());
Assert.AreEqual(2, custom.ValidationErrorMessages.Length); // Email + Post 失敗
}
類別結構:
AbstractValidationAttribute:標註在 Property 上,持有 Validator 實例AbstractValidator:實作 IValidator,核心邏輯在 Perform(object instance, object fieldValue)範例:自訂「大於零」驗證
[Serializable]
public class ValidatePositiveAttribute : AbstractValidationAttribute {
public ValidatePositiveAttribute() : base(new PositiveValidator()) { }
public ValidatePositiveAttribute(string errorMessage) : base(new PositiveValidator(), errorMessage) { }
}
[Serializable]
public class PositiveValidator : AbstractValidator {
public override bool Perform(object instance, object fieldValue) {
if (fieldValue == null) return false;
return Convert.ToDecimal(fieldValue) > 0;
}
protected override string BuildErrorMessage() {
return $"{Property.Name} 必須大於零";
}
}
// 使用
[Property, ValidatePositive]
public decimal Amount { get; set; }
ActiveRecordValidationBase 建構子呼叫 CollectValidators(),透過 ActiveRecordModel 掃描所有 Property 上的 AbstractValidationAttribute,取出對應 Validator 存入 ArrayList __validators。IsValid() 時,逐一呼叫 validator.Perform(this)(傳入實體本身),失敗則收集 validator.ErrorMessage 至陣列。OnSave/OnUpdate/OnDelete,自動呼叫 IsValid(),驗證失敗拋出 ValidationException 並回滾交易。若驗證涉及昂貴運算(如遠端 API 呼叫),可先用 Logger.ShouldLog(logEntry) 預檢是否會被過濾,決定是否執行完整驗證邏輯。
ActiveRecord 驗證框架提供開箱即用的聲明式驗證,支援擴展且整合交易攔截。善用內建屬性覆蓋 80% 場景,複雜規則透過自訂 Validator 封裝,保持模型純淨與職責單一。