2014年12月18日 星期四

Entity Framework DbContext Validation API

先建一張資料表,並加上幾個Attribute當例子
namespace ConsoleApplication1.Models
{
    using System;
    using System.ComponentModel.DataAnnotations;
    using System.ComponentModel.DataAnnotations.Schema;

    [Table("Table1")]
    public class Table1
    {
        [Key]
        public int Table1Id { get; set; }

        [Required]
        [StringLength(10, MinimumLength = 2)]
        public string C1 { get; set; }

        [Range(10, 20)]
        public int C2 { get; set; }

        public DateTime D1 { get; set; }

        public DateTime D2 { get; set; }
    }
}

針對屬性驗證
namespace ConsoleApplication1
{
    using ConsoleApplication1.Models;
    using System;
    using System.Data.Entity;

    class Program
    {
        static void Main(string[] args)
        {
            Database.SetInitializer(new DropCreateDatabaseAlways<DemoContext>());
            using (DemoContext db = new DemoContext())
            {
                db.Database.Initialize(false);

                Table1 table1 = new Table1
                {
                    C1 = "a",
                    C2 = 1,
                    D1 = DateTime.Now,
                    D2 = DateTime.Now.AddDays(-1)
                };

                foreach (var item in db.Entry(table1).Property(x => x.C1).GetValidationErrors())
                {
                    Console.WriteLine(item.ErrorMessage);
                }

                foreach (var item in db.Entry(table1).Property(x => x.C2).GetValidationErrors())
                {
                    Console.WriteLine(item.ErrorMessage);
                }
            }
        }
    }
}

針對實體驗證
namespace ConsoleApplication1
{
    using ConsoleApplication1.Models;
    using System;
    using System.Data.Entity;

    class Program
    {
        static void Main(string[] args)
        {
            Database.SetInitializer(new DropCreateDatabaseAlways<DemoContext>());
            using (DemoContext db = new DemoContext())
            {
                db.Database.Initialize(false);

                Table1 table1 = new Table1
                {
                    C1 = "a",
                    C2 = 1,
                    D1 = DateTime.Now,
                    D2 = DateTime.Now.AddDays(-1)
                };

                foreach (var item in db.Entry(table1).GetValidationResult().ValidationErrors)
                {
                    Console.WriteLine(item.ErrorMessage);
                }
            }
        }
    }
}

針對DbContext驗證
namespace ConsoleApplication1
{
    using ConsoleApplication1.Models;
    using System;
    using System.Data.Entity;

    class Program
    {
        static void Main(string[] args)
        {
            Database.SetInitializer(new DropCreateDatabaseAlways<DemoContext>());
            using (DemoContext db = new DemoContext())
            {
                db.Database.Initialize(false);

                Table1 table1 = new Table1
                {
                    C1 = "a",
                    C2 = 1,
                    D1 = DateTime.Now,
                    D2 = DateTime.Now.AddDays(-1)
                };

                db.Table1.Add(table1);
                foreach (var result in db.GetValidationErrors())
                {
                    foreach (var item in result.ValidationErrors)
                    {
                        Console.WriteLine(item.ErrorMessage);
                    }
                }
            }
        }
    }
}

輸出的畫面如下

自定義驗證屬性規則,加入一個靜態類別,用來放自定義的驗證規則
namespace ConsoleApplication1.Models
{
    using System.ComponentModel.DataAnnotations;

    public static class MyCustomRule
    {
        public static ValidationResult MyStringRule(string value)
        {
            if (value == "a")
            {
                return new ValidationResult("字串不可為a");
            }
            else
            {
                return ValidationResult.Success;
            }
        }

        public static ValidationResult MyIntRule(int value)
        {
            if (value == 1)
            {
                return new ValidationResult("數字不可為1");
            }
            else
            {
                return ValidationResult.Success;
            }
        }
    }
}

在屬性上加入自定義的驗證規則
namespace ConsoleApplication1.Models
{
    using System;
    using System.ComponentModel.DataAnnotations;
    using System.ComponentModel.DataAnnotations.Schema;

    [Table("Table1")]
    public class Table1
    {
        [Key]
        public int Table1Id { get; set; }

        [Required]
        [StringLength(10, MinimumLength = 2)]
        [CustomValidation(typeof(MyCustomRule), "MyStringRule")]
        public string C1 { get; set; }

        [Range(10, 20)]
        [CustomValidation(typeof(MyCustomRule), "MyIntRule")]
        public int C2 { get; set; }

        public DateTime D1 { get; set; }

        public DateTime D2 { get; set; }
    }
}

驗證資料的時後,就會包含自定義的規則

自定義驗證實體規則,在實體上實作IValidatableObject介面
namespace ConsoleApplication1.Models
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel.DataAnnotations;
    using System.ComponentModel.DataAnnotations.Schema;

    [Table("Table1")]
    public class Table1 : IValidatableObject
    {
        [Key]
        public int Table1Id { get; set; }

        [Required]
        // [StringLength(10, MinimumLength = 2)]
        public string C1 { get; set; }

        // [Range(10, 20)]
        public int C2 { get; set; }

        public DateTime D1 { get; set; }

        public DateTime D2 { get; set; }

        public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
        {
            if (this.C1 == "a")
            {
                yield return new ValidationResult("字串不可為a");
            }

            if (this.C2 == 1)
            {
                yield return new ValidationResult("數字不可為1");
            }

            if (this.D1 >= this.D2)
            {
                yield return new ValidationResult("d1不能大於d2");
            }
        }
    }
}

自定義驗證DbContext規則,覆寫ValidateEntity函式
namespace ConsoleApplication1.Models
{
    using System.Collections.Generic;
    using System.Data.Entity;
    using System.Data.Entity.Infrastructure;
    using System.Data.Entity.Validation;

    public class DemoContext : DbContext
    {
        public DbSet<Table1> Table1 { get; set; }
        public DbSet<Table2> Table2 { get; set; }

        protected override DbEntityValidationResult ValidateEntity(DbEntityEntry entityEntry, IDictionary<object, object> items)
        {
            var result = base.ValidateEntity(entityEntry, items);
            var table1 = entityEntry.Entity as Table1;
            if (table1 != null)
            {
                if (table1.C1 == "a")
                {
                    result.ValidationErrors.Add(new DbValidationError("C1", "字串不可為a"));
                }

                if (table1.C2 == 1)
                {
                    result.ValidationErrors.Add(new DbValidationError("C2", "數字不可為1"));
                }

                if (table1.D1 >= table1.D2)
                {
                    result.ValidationErrors.Add(new DbValidationError("D1", "d1不能大於d2"));
                }
            }

            return result;
        }
    }
}
輸出的結果如下