轉帖|其它|編輯:郝浩|2010-11-08 13:56:49.000|閱讀 1171 次
概述:本文主要講解如何在在MVC2.0 中 進行 LINQTOSQL 實體統一驗證方法,希望對大家有幫助。
# 界面/圖表報表/文檔/IDE等千款熱門軟控件火熱銷售中 >>
場景:
當我把項目從 MVC1.0 升級到 MVC2.0 時,原以為可以方便的使用System.ComponentModel.DataAnnotations 結合 MVC2.O 的
ModelState.IsValid 進行數據有效驗證。比如以下驗證:
public class SystemUserMetaData
{
[Required(ErrorMessage = "不能為空!")]
[StringLength(6, ErrorMessage = "用戶名長度不能超過6!")]
public string UserName { get; set; }
[Required(ErrorMessage = "中文名不能為空")]
public string ChineseName { get; set; }
[Required(ErrorMessage = "部門不能為空")]
public int DepartmentID { get; set; }
[Required(ErrorMessage = "密碼不能為空")]
public string Password { get; set; }
[Required(ErrorMessage = "職位不能為空")]
public int RankID { get; set; }
[PhoneAttribute(ErrorMessage = "電話號碼不正確")]// 自定義ValidationAttribute “只能驗證 MobilePhone 的值”
public string MobilePhone { get; set; }
public int UserID { get; set; }
}
這些Annotation特性驗證可以很輕松通過 mvc2.0 ViewData.ModelState.Values 獲取到驗證錯誤的提示信息。但是當我們的驗證條件變得更加復雜時,比如在修改一個LinqToSQL 實體時需通過該實體的主鍵和唯一索引進行驗證實體是否唯一性時,此時需要兩個字段同時驗證,當這種驗證出現時我發現無法簡單的使用 DataAnnotaion 進行同一實體的多字段驗證。自定義 ValidationAttribute 特性重寫 IsValid 時 無法根據當前的屬性獲取到其他屬性的值。因為ValidationAttribute 特性是附加在一個類的屬性上的。可能聰明的你此刻已想到了將驗證特性直接加載 LinqToSQL 的 類上。當你為這個特性編寫驗證方法時就可以通過反射得到 LinqToSql 實體的所有屬性的值,或許單一的 ValidationAttribute 屬性驗證特性不能完成的任務就可以得到解決。
當我把LINQTOSQL 類的驗證特性寫完后附加到 LinqTOSQL partial 類上代碼如下:
[UniqueName("UserID", "UserName", typeof(SystemUser), ErrorMessage = "該用戶已存在。")]
[MetadataType(typeof(SystemUserMetaData))]
public partial class SystemUser { }
在MVC2.0 中當我們使用 TryUpdateModel 方法時 發現 UniqueName 的 IsValid 方法始終沒有被調用。但是當 MetadataType 移除除掉,我們再調用TyUpdateaModel方法時UniqueName 特性的 IsValid 驗證方法就被正常調用了。此時我明白了問題應該是由 MVC TryUpdateModel 方法引起,將該方法換成 UpdateModel 后問題依舊。MetadataType 特性覆蓋了 UniqueName 特性,當然了如果想知道具體的原因,可以 Reflect 出 TryUpdateModel 的方法找到到答案。為了解決這個問題,我決定使用自定義的方法進行實體驗證,代碼如下:
public class Validation
{
public static void ValidateAttributes<TEntity>(TEntity entity)
{
var validationInstance = new Validation();
validationInstance.ValidateAttributesInternal(entity);
}
public virtual void ValidateAttributesInternal<TEntity>(TEntity entity)
{
var validationIssues = new List<ValidationIssue>();
var props = typeof(TEntity).GetProperties();
var metatype = typeof(TEntity).GetCustomAttributes(typeof(MetadataTypeAttribute), false).FirstOrDefault();
var type = ((System.ComponentModel.DataAnnotations.MetadataTypeAttribute)(metatype)).MetadataClassType;
var s = type.GetProperties();
var customAttrs = typeof(TEntity).GetCustomAttributes(true).Where(t => t.GetType().Namespace.Contains("ValidationMeta"));
foreach (var attr in customAttrs)
{
var validate = (ValidationAttribute)attr;
//執行 附加在 linqtosql partial 類 上的 ValidationAttribute 驗證方法
bool valid = validate.IsValid(entity);
if (!valid)
{
validationIssues.Add(new ValidationIssue(null, null, validate.ErrorMessage));
}
}
//執行附加在 linqtosql partial 類 屬性上的 ValidationAttribute 驗證方法
foreach (var prop in s)
ValidateProperty(validationIssues, entity, prop);
// throw exception?
if (validationIssues.Count > 0)
throw new ValidationIssueException(validationIssues);
}
protected virtual void ValidateProperty<TEntity>(List<ValidationIssue> validationIssues, TEntity entity, PropertyInfo property)
{
//得到驗證特性的集合
var validators = property.GetCustomAttributes(typeof(ValidationAttribute), false);
foreach (ValidationAttribute validator in validators)
ValidateValidator(validationIssues, entity, property, validator);
}
protected virtual void ValidateValidator<TEntity>(List<ValidationIssue> validationIssues, TEntity entity, PropertyInfo property, ValidationAttribute validator)
{
var dataEntityProperty = typeof(TEntity).GetProperties().FirstOrDefault(p => p.Name == property.Name);
var value = dataEntityProperty.GetValue(entity, null);
if (!validator.IsValid(value))
{
validationIssues.Add(new ValidationIssue(property.Name, value, validator.ErrorMessage));
}
}
}
大家留意一下代碼3 中的注釋,這樣 Validation 這個類就就可以替代MVC TryUpdateModel 的驗證功能同時讓代碼1的 UniqueName 和 MetaDataType 兩個特性 “共存”。
MetadataType 的職責:驗證實體的單一屬性值的有效性。
LINQ實體類上的其他的自定義特性:如代碼1中的 UniqueName 則可以進行復雜的屬性驗證如多屬性值同時驗證等。
這樣我們就徹底的解決了開發過程中驗證代碼統一的編碼規范。而不是同一個數據有效性驗證的代碼滿天飛的局面。
小結:
當我完成了以上代碼似乎已經達到了預期的目的,但測試代碼時候發現如果使用TryUpdateModel 更新另外一個LINQTOSQL 模型(Order表),這個被
更新的模型從數據庫上來看它屬于 SystemUser 的外鍵表。通過Order表中的UserID 字段關聯到 SystemUser。當Order實體被MVC TryUpdateModel 時會同時把SystemUser 的 自定義的 [UniqueName] 特性的方法 IsValid() 也調用了,很顯然這不是我們想要的。該問題我會在下一篇文章提出解決方案。
本站文章除注明轉載外,均為本站原創或翻譯。歡迎任何形式的轉載,但請務必注明出處、不得修改原文相關鏈接,如果存在內容上的異議請郵件反饋至chenjj@fc6vip.cn
文章轉載自:網絡轉載自RyanDing