FluentAPI深入

1.  HasMaxLenght 设定字段得最大长度:

        static void Main(string[] args)
        {
            using (TestDbContext ctx = new TestDbContext())
            {

              
                Person p = new Person
                {
                    Name = "chenwwwwwwwwwwwwwwwwwwwwww",
                    Age=12,
                    CreateDateTime=DateTime.Now
                };
                ctx.Persons.Add(p);
                try
                {
                    ctx.SaveChanges();
                }
                catch (DbEntityValidationException ex)
                {
                    foreach (var e in ex.EntityValidationErrors)
                    {
                        foreach (var error in e.ValidationErrors)
                        {
                            Console.WriteLine(error.ErrorMessage);
                        }
                    }  
                     
                }
               
                Console.ReadKey();
            }
        }

      依赖于数据库得“字段长度、是否为空”等约束是在数据提交到数据库服务器得时候才会检查‘EF得配置,则是由EF来检查得,如果检查出错根本不会被提交给服务器。

2.  (有用)字段是否为空:

        public PersonConfig()
        {
            this.ToTable("T_Persons");
            this.Property(p=>p.Name).HasMaxLength(20);
            this.Property(p => p.Name).IsRequired();//属性不能为空
            this.Property(p => p.Name).IsOptional();//属性可以为空
        }  

           默认规则是“主键属性不允许为空,引用类型允许为空”

        public PersonConfig()
        {
            this.ToTable("T_Persons");
            this.HasKey(p => p.Id); //主键
            this.Property(p => p.Name).IsFixedLength(); //是否对应固定得长度
            this.Property(p => p.Name).IsUnicode(false);//对应得数据库类型是varchar类型,而不是nvarchar
            this.Property(p => p.Name).HasColumnName("Names"); //Name对应数据库中得字段名是Names
            this.Ignore(p => p.Name);//某个字段不参与映射数据库
        }   

3、一对多

        和关系映射相关得方法:

        (1) 基本套路  this.Has****(p=>p.A).With****()  当前这个表和A属性表的关系是Has定义,  With定义的是A对应的表和这个表的关系。

        (2)  HasOptional()   有一个是可选的(可以为空的);   HasRequlred() 有一个是必须的(不能为空的);    HasMany() 有很多的; 

        (3)WithOptional() 可选的;     WithRequired() 必须的   ;  WithMany() 很多的;

          实例一:

         

  public  class Student
    {
        public long Id { get; set; }
        public string Name { get; set; }
        public int Age { get; set; }
        public long ClassId { get; set; }
        public virtual  Class Class { get; set; }
    }
   public class Class
    {
        public long Id { get; set; }

        public string Name { get; set; }
        public int Count { get; set; }

    }
  public class ClassConfig:EntityTypeConfiguration<Class>
    {
        public ClassConfig()
        {
            ToTable("T_Classes");
        }
    }
   public  class StudentConfig:EntityTypeConfiguration<Student>
    {
        public StudentConfig()
        {
            ToTable("T_Students");
        }    
    }
                Class c1 = new Class()
                {
                    Name = "三年一班",
                };


                Student s1 = new Student()
                {
                    Name = "chen",
                    Age = 12,
                    Class = c1
                };

                
                ctx.Students.Add(s1);
                ctx.SaveChanges();

       实例二:

                var  s = ctx.Classes.First();

                //双向设计,容易搞混
                /*
                foreach (var item in s.Students)
                {
                    Console.WriteLine(item.Name);
                }
                */
                //数据库化思维,推荐用这种用法
                foreach (var item in ctx.Students.Where(p => p.ClassId == s.Id))
                {
                    Console.WriteLine(item.Name);
                }
    public class Class
    {
        public long Id { get; set; }

        public string Name { get; set; }
        public int Count { get; set; }
        public virtual ICollection<Student> Students { get; set; } = new List<Student>(); //这里就可以获得所有指向了当前对象的Student集合,不推荐这种双向设计关系

    }

4、 多对多

   public  class Teacher
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public virtual ICollection<Student> Students { get; set; } = new List<Student>();

    }

  public  class Student
    {
        public long Id { get; set; }
        public string Name { get; set; }
        public int Age { get; set; }
        public long? Class_Id { get; set; }

        public virtual  Class Class { get; set; }
        public virtual ICollection<Teacher>  Teachers { get; set; } = new List<Teacher> ();


    }
   public  class StudentConfig:EntityTypeConfiguration<Student>
    {
        public StudentConfig()
        {
            ToTable("T_Students");
            this.HasRequired(s => s.Class).WithMany().HasForeignKey(e => e.Class_Id);
        }    
    }

  public  class TeacherConfig:EntityTypeConfiguration<Teacher>
    {
        public TeacherConfig()
        {
            ToTable("T_Teachers");
            this.HasMany(e => e.Students).WithMany(e=>e.Teachers).Map(e => e.ToTable("T_TeacherStudentRelations").MapLeftKey("teacherId").MapRightKey("studentId"));
        }
    }
        static void Main(string[] args)
        {
            using (TestDbContext ctx = new TestDbContext())
            {

                Teacher t1 = new Teacher()
                {
                    Name = "语文老师"
                };
                Teacher t2 = new Teacher()
                {
                    Name = "数学老师"
                };

                Student s1 = new Student()
                {
                    Name = "小李",
                    Age = 23
                };
                Student s2 = new Student()
                {
                    Name = "小王",
                    Age = 33
                };
                Student s3 = new Student()
                {
                    Name = "小章",
                    Age = 33
                };
                t1.Students.Add(s1);
                t1.Students.Add(s2);
                t2.Students.Add(s2);
                t2.Students.Add(s3);


                ctx.Teachers.Add(t1);
                ctx.Teachers.Add(t2);

                ctx.SaveChanges();

                Console.ReadKey();

            }
        }

                    总结:  (1)一对多中不建议配置一端的集合属性,因此配置的时候不用给WithMany()参数,如果配置了集合属性,则必须给WithMany参数;多对多关系必须要给WithMany参数

                                 (2) 多对多移除关系: 

        static void Main(string[] args)
        {
            using (TestDbContext ctx = new TestDbContext())
            {
               var t=ctx.Teachers.Single(p=>p.Name=="数学老师");
               var s = ctx.Students.Single(p => p.Name == "小章");
                t.Students.Remove(s);

                ctx.SaveChanges();

                Console.ReadKey();

            }
        }

                             (3)如果数据库创建好了再修改模型或者配置,运行就会报错,那么就要手动删除数据库或者

 Database.SetInitializer(new DropCreateDatabaseIfModelChanges<TestDbContext>());

                             (4)做项目时建议初期先把主要的类使用EF自动生成表,然后干掉Migration表,然后

Database.SetInitializer<TestDbContext>(null);   //禁止DbMigration使用,手动修改实体类和数据库

5、延迟加载:

          延迟加载(lazy load) ,只有用到关联的对象的数据,才会再去指向select查询,注意延迟加载只在关联对象属性上,普通属性没有这个东西;

          注意启用延迟加载需要配置如下的两个属性(默认是true,因此不需要配置,只要别手动设置为false即可)

            context.Configuration..ProxyCreationEnable=true;     context.Configuration..LazyLoadingEnable=true;

          分析延迟加载的原理:打印一下拿到的对象的GetType(),再打印一下GetType().BaseType;我们发现拿到的对象其实是Student子类的对象(如果结果不一致,说明类不是Public,没有关联的virtua属性l)

           延迟加载的优点: 用到的时候才加载,没用到的时候不加载,避免了一次性加载所有的数据,提高了加载速度。缺点: 如果不用延迟加载,就可以一次数据库查询所有数据(join实现),用了延迟加载就要多次的执行数据库操作,提高了数据库服务器的压力

            因此:如果关联的属性几乎都要读到,那么就不要用延迟加载;如果关联的属性只有较小的概率则可以启动延迟记载;

 6、不延迟加载,怎样一次加载?

          又想方便(必须是virtual)又想效率高!用EF永远都要把导航属性设置为virtual。

           使用Include()方法:

             (1)var s= ctx.Students.Include("Class").First();   //Include("Class")的意思是直接加载student的Class属性的数据。注意只有关联的对象属性才可以用Include,普通字段不可以;

              (2) C#6.0 语法糖,可以使用nameof语法解决这个问题:

                          ctx.Students.Include(nameof(Student.Class)).First();

              (3)      //using System.Data.Entity;   推荐这种做法

                               ctx.Students.Include(e=>e.Class).First();

                       如果有多个属性需要一次性加载,也可以写多个Include:         

               (4)

            using (TestDbContext ctx = new TestDbContext())
            {
                foreach (var s in ctx.Students)
                {
                    Console.WriteLine(s.Name);
                    Console.WriteLine(s.Class.Name);
                }
            }   //报错,多个DataReader一起执行了

                     三种解决方法:

                           在字符串上加上:MultipleActiveResultSets=true; 但是不支持其他数据库

                           执行一下Tolist()  ,因为Tolist() 就遍历然后生成list:

            using (TestDbContext ctx = new TestDbContext())
            {
                foreach (var s in ctx.Students.ToList())
                {
                    Console.WriteLine(s.Name);
                    Console.WriteLine(s.Class.Name);
                }
            }

                           推荐做法:Include预先加载: 

            using (TestDbContext ctx = new TestDbContext())
            {
                foreach (var s in ctx.Students.Include(e=>e.Class))
                {
                    Console.WriteLine(s.Name);
                    Console.WriteLine(s.Class.Name);
                }
            }

                        

原文地址:https://www.cnblogs.com/fuyouchen/p/9413943.html