zoukankan      html  css  js  c++  java
  • Entity Framework 4.1/4.3 之七 (DBContext 之4 数据验证) jerry

     

    Entity Framework 4.1/4.3 之七 (DBContext 之4  数据验证)

     

      中国男篮输了,不过不影响我对中国男篮的喜欢。在Entity Framework 4.1/4.3 之六 (DBContext 3)中讲了EF DBContext API的常用功能,今天来我们接着来讲一下DBContext API的验证。

     

    三、DBContext 的验证 (Validating with the Validation API) 

      1、定义和触发验证 (Defining and Triggering Validation)

        会引起DBContext去执行验证的一些方法

        (1)、当跟踪状态为增加、修改时。调用执行SaveChanges()方法会执行验证。

        (2)、DbEntityEntry.GetValidationResult() 方法将会对单独的Object执行验证。

        (3)、DbEntityEntry

        (4)、DbContext.GetValidationErrors 可以在DBContext进行 增加、修改实体的时候不捕获验证异常。

        我们来描述一下验证的流程:

        DBContext.SaveChanges()这时候调用验证 —> DBContext.GetValidationErrors —> DBContext.ValidateEntity(CustomLogic) —> DBEntityEntry.GetValidationResult(ValidationAttribute,IValidatableObject.Validate)

     

        2、验证单个实体并获取验证结果  (Validating a Single Object on Demand with GetValidationResult)

        代码如下,先是在实体中对属性进行约束,我们来看一下代码:

          [MaxLength(500)]
          public string Description { get; set; }    
          [MaxLength(10)]      
          public string LastName { get; set; }
    
          private static void ValidateNewPerson()
          {
            var person = new Person
            {
              FirstName = "Julie",
              LastName = "Lerman",
              Photo = new PersonPhoto { Photo = new Byte[] { 0 } }
            };
            using (var context = new BreakAwayContext())
            {
              if (context.Entry(person).GetValidationResult().IsValid)
              {
                Console.WriteLine("Person is Valid");
              }
              else
              {
                Console.WriteLine("Person is Invalid");
              }
            }
          }  

    输出的结果是:Person is Valid

      代码真是个好东西,他能让我们一下子就明白,原来是这么回事。[MaxLength(500)]好定了内容的长度,这个特性需要引用using System.ComponentModel.DataAnnotations; 如果你试着把LastName的属性值改为超为10长度的字符串,得到的结果会是InValidate也就是False,不信你试试。对了,GetValidationResult()是用来获取验证的结果。
        

      3、通过DataAnnotations来指定属性的验证规则 (Specifying Property Rules with ValidationAttribute DataAnnotations)

        下面列出的是DataAnnotations验证的方式:

       可以限定字条串的长度、数值的大小、还可以自定义表达式、

          DataTypeAttribute
           [DataType(DataType enum)]
    
          RangeAttribute       [Range (low value, high value, error message
    string)]
          RegularExpressionAttribute       [RegularExpression(@”expression”)]
          RequiredAttribute       [Required]
          StringLengthAttribute       [StringLength(max length value,       MinimumLength
    =min length value)]
          CustomValidationAttribute       This attribute can be applied to a type
    as well as to a property.

            

       Entity Framework 提供了MaxLengthAttribute 和 MinLengthAttribute。为了符合代码先行的理念,DBContext 的验证API中提代了很多方法,利用这些方法,我们就可以直接在编写代码的时候来对属性设置约束。我们来看个例子: 

        modelBuilder.Entity<TestEntity>().Property(p => p.name).HasMaxLength(10);
     

       例子设定了TestEntity实体的name属性的最大长度为10。通过这种方式,我们就可以在DBContext.OnModelCreating 方法中加入上面的代码来代替[MaxLength]方式的特性限定。你可以试试这种新的方式,试之前记得把实体中的[MaxLength]去掉,同样调用GetValidationResult()来获取验证的结果。

     

       对临时属性的验证 (Validating Unmapped or “Transient” Properties)

       有这样一种情况,在实体中有些属性并没有和数据库中字段有映射关系。只是我们为了处理业务而临时加的属性,如果我们给这处临时属性加上特性约束后,Entity Framework同样会对其进行验证。

     

       4、检查验证结果的详细信息 (Inspecting Validation Result Details)

       我们注意到GetValidationResult 在验证失败后并不是简单的返回或者说抛出一个exception。而是返回一个System.Data.Entity.Validation.DbEntityValidationResult 类型的值。DbEntityValidationResult 也公来了一个ValidationErrors属性,这个属性包含记录了详细错误信息的DbValidationError类型集合。下图展示了获取验证结果,包含IsValid值(是否验证通过的值),和ValidationErrors属性。

       错误提示:当我们把LastName的属性值赋值超过了约束限定大小时,返回ValidationErrors验证结果,它包含一个单独的DbValidationError。DbValidationError有两个属性,一个是发生异常对应的属性名称,一个是错误信息。这里有一个疑问?错误消息是哪儿来的呢???我们可以自己定义错误消息吗???  我们来看看代码:

        [MaxLength(10,ErrorMessage= "Dude! Last name is too long! 10 is max.")]
        public string LastName { get; set; }

       通过代码我们看到了,错误信息来源于我们属性约束值提供的错误消息。当然,如果你不写也没关系,EF会自己提供错误消息。以就是上图展示的ErrorMessage。下图将展示出我们自定义的错误消息:

     

       5、深入探索属性验证 (Exploring More Validation Attributes)

       (1)、表达式验证

        [RegularExpression(@"^[a-zA-Z''-'\s]{1,40}$")]
        public string Country { get; set; }
        public static void ValidateDestination()
        {
          ConsoleValidationResults(
          new Destination
          {
            Name = "Bei Jing City",
            Country = "China",
            Description = "Big city"
          });
        }

       如果你试着把Country的值改为 C.H.I.N.A 就会出现验证异常。因为C.H.I.N.A与正则不匹配。
       (2)、使用自定义的属性验证 

        using System.ComponentModel.DataAnnotations;
        namespace Model
        {
          public static class BusinessValidations
          {
            public static ValidationResult DescriptionRules(string value)
            {
              var errors = new System.Text.StringBuilder();
              if (value != null)
              {
                var description = value as string;
                if (description.Contains("!"))
                {
                  errors.AppendLine("Description should not contain '!'.");
                }
                if (description.Contains(":)") || description.Contains(":("))
                {
                  errors.AppendLine("Description should not contain emoticons.");
                }
            }
            if (errors.Length > 0)
              return new ValidationResult(errors.ToString());
            else
              return ValidationResult.Success;
          }
        }
       }

       提示:你可以看到难证结果此处是System.ComponentModel.DataAnnotations.ValidationResult 类型。

       好了,验证的功能写好了,下面我们来使用一下自己的验证。

        [MaxLength(500)]
        [CustomValidation(typeof(BusinessValidations), "DescriptionRules")]
        public string Description { get; set; }

       如果你愿意的话,自己写个测试,使用GetValidationResult 来测试吧。

       (3)、在请求中验证属性 (Validating Individual Properties on Demand)  

       除了提供getvalidationresults方法,dbentityentry 也可以让你进行属性验证:

                 context.Entry(trip).Property(t => t.Description);

       它会返回一个 DbPropertyEntry 类来描述属性。DbPropertyEntry 类有明确的方法(GetValidationErrors)来验证特定项目。这个方法将返回ICollection<DbValidationError>,它与 DbValidationError 类型相同。我们通过下面这个例子来看看GetValidationErrors的应用。

        private static void ValidatePropertyOnDemand()
        {
          var trip=new Trip
          {
            EndDate = DateTime.Now,
            StartDate = DateTime.Now,
            CostUSD = 500.00M,
            Description = "Hope you won't be freezing :)"
          };
          using (var context = new BreakAwayContext())
          {
            var errors = context.Entry(trip).Property(t => t.Description).GetValidationErrors();
            Console.WriteLine("# Errors from Description validation: {0}",
            errors.Count());
          }
        }

     

       (4)、使用IValidatableObject接口来进验证

       除了ValidationAttribute,.Net 4 新增了IValidatableObject 接口供开发者进行业务逻辑验证。IValidatableObject 提供了Validate 方法供开发者自己来扩展自定义验证。我们来看例子:

        public class Trip : IValidatableObject
        {
          [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
          public Guid Identifier { get; set; }
          public DateTime StartDate { get; set; }
          public DateTime EndDate { get; set; }
          [CustomValidation(typeof(BusinessValidations), "DescriptionRules")]
          public string Description { get; set; }
          public decimal CostUSD { get; set; }
          [Timestamp]
          public byte[] RowVersion { get; set; }
          public int DestinationId { get; set; }
          [Required]
          public Destination Destination { get; set; }
          public List<Activity> Activities { get; set; }
    
          public IEnumerable<ValidationResult> Validate(         ValidationContext validationContext)         {           if (StartDate.Date >= EndDate.Date)           {             yield return new ValidationResult(               "Start Date must be earlier than End Date",               new[] { "StartDate", "EndDate" });           }         }     }

       Trip 继续 IValidatableObject 并实现 接口方法Validate,在Validate方法中加入了自己的验证逻辑。我们来测试一下这个验证,下面是测试代码:

        private static void ValidateTrip()
        {
          ConsoleValidationResults(new Trip
          {
            EndDate = DateTime.Now,
            StartDate = DateTime.Now.AddDays(2),
            CostUSD = 500.00M,
            Destination = new Destination { Name = "Somewhere Fun" }
          });
        }

       当我们调用ValidateTrip, 程序会显示 “Start Date must be earlier than End Date.”   这种Validate 验证方式我们多在MVC和WPF编程中用到,帮绑定属性的时候可以把错误提示也一便绑定了。

     

       (5)、使用CustomValidationAttributes 进行验证 以下是代码:代码可以很好的说明

        public static ValidationResult TripDateValidator(
              Trip trip,
              ValidationContext validationContext)
        {
          if (trip.StartDate.Date >= trip.EndDate.Date)
          {
            return new ValidationResult(
              "Start Date must be earlier than End Date",
              new[] { "StartDate", "EndDate" });
            }
            return ValidationResult.Success;
          }
    
        public static ValidationResult TripCostInDescriptionValidator(           Trip trip,           ValidationContext validationContext)     {       if (trip.CostUSD > 0)       {         if (trip.Description.Contains(Convert.ToInt32(trip.CostUSD).ToString()))         {           return new ValidationResult(             "Description cannot contain trip cost",             new[] { "Description" });         }       }       return ValidationResult.Success;     }

    这是我们自己写的自己定义的验证方法,下面我们来使用自定义方法:
        [CustomValidation(typeof(Trip), "TripDateValidator")]
        [CustomValidation(typeof(Trip), "TripCostInDescriptionValidator")]
        public class Trip: IValidatableObject

       下面是测试程序:

        private static void ValidateTrip()
        {
           ConsoleValidationResults(new Trip
            {
            EndDate = DateTime.Now,
            StartDate = DateTime.Now.AddDays(2),
            CostUSD = 500.00M,
            Description = "You should enjoy this 500 dollar trip",
            Destination = new Destination { Name = "Somewhere Fun" }
            });
          }


          关于DBContext验证就先讲到这里,也不知道有没有讲清楚,有效的验证可以为我们提供安全,当然内容中提到的也并不是也好用。大家分场合使用。发挥各自优势。我是百灵,我们下回见。

  • 相关阅读:
    第九周作业
    第八周
    第七周
    Jmeter连接到Mysql
    数据库常用链接URL写法
    功能测试方法
    常建输入框的测试
    系统业务流程测试(转)
    Linux
    搭建Git服务器
  • 原文地址:https://www.cnblogs.com/mbailing/p/2621356.html
Copyright © 2011-2022 走看看