2012年4月13日星期五

MVC验证(自动在基类中验证实体的数据有效性),本人最满意的作品之一

MVC验证(自动在基类中验证实体的数据有效性),本人最满意的作品之一



说起数据验证,在我的博客中文章不少,有MVC标准验证,有自己架构中用到的验证,但一个共同的问题就是重复的代码量太大,而且破坏了数据库实体本身的层次感!即数据(实体)有效性验证就应该在实体层去实现,不应该推迟到WEB层去做这事,在之前的文章中我介绍了使用统一实体基类来做这事,但需要每个实体都去干预自己的部分(可能大部分情况下,每个实体的某些验证都是相同的,如非空验证),这样,对于懒惰的程序员来说,是件很不爽的事,于是乎,开始想去解决这个问题了。

原来的代码:

public virtual bool IsValid { get { return (this.GetRuleViolations().Count() == 0); } }   public abstract IEnumerable<RuleViolation> GetRuleViolations();在派生类中去实现这个GetRuleViolations()方法:
public override IEnumerable<RuleViolation> GetRuleViolations()     {            if (this.ConfirmPassword != this.Password && this.ConfirmPassword != this.NewPassword)             yield return new RuleViolation("两?次?密ü码?必?须?相à同?", "ConfirmPassword");     }像上面的代码其实只是作了非空性验证,正常情况下,我们需要为每个非空的字段(属性)去做这样的验证,太悲哀了,于是,想到了下面的解决方法,将非空验证提取到基类中去做这事。
  #region 实体验证
    public virtual bool IsValid { get { return (this.GetRuleViolations().Count() == 0); } }       public virtual IEnumerable<RuleViolation> GetRuleViolations()        {           PropertyInfo[] propertyInfo = this.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);            foreach (var i in propertyInfo)            {                if (i.GetCustomAttributes(typeof(System.Data.Linq.Mapping.ColumnAttribute), false) != null                    && i.GetCustomAttributes(typeof(System.Data.Linq.Mapping.ColumnAttribute), false).Count() > 0                    && !((System.Data.Linq.Mapping.ColumnAttribute)i.GetCustomAttributes(typeof(System.Data.Linq.Mapping.ColumnAttribute), false)[0]).CanBeNull                    && !((System.Data.Linq.Mapping.ColumnAttribute)i.GetCustomAttributes(typeof(System.Data.Linq.Mapping.ColumnAttribute), false)[0]).IsPrimaryKey)                    if (i.GetValue(this, null) == null || string.IsNullOrEmpty(i.GetValue(this, null).ToString()))                        yield return new RuleViolation("*", i.Name);            }        }         #endregion我们可以看到,基类中的GetRuleViolations() 已经被改造成了虚方法,即它要去做一些派生类共用的工作,本例是“非空验证”,而如果有个性化的验证,还是需要在指定的实体中去实现,代码可能是这样:
public override IEnumerable<RuleViolation> GetRuleViolations()       {           #region 得到基类的非空验证迭代结果
          foreach (var violation in base.GetRuleViolations())               yield return violation;           #endregion           if (this.ConfirmPassword != this.Password && this.ConfirmPassword != this.NewPassword)               yield return new RuleViolation("两?次?密ü码?必?须?相à同?", "ConfirmPassword");       }

恩,这样的设计我才算是满意,一句话,共用的放在基类的虚方法,个性化的需要在实体类中复写基类方法,通过override关键字可以复写基类的抽象或方法,而不会覆盖掉它们,再配合base关键字,就可以调用基类的方法了,呵呵。



TAG: