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关键字,就可以调用基类的方法了,呵呵。

posted @ 2012-04-13 00:02  张占岭  阅读(1960)  评论(2编辑  收藏  举报