FluentAPI深入

Posted 鬼草道人

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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实现),用了延迟加载就要多次的执行数据库操作,提高了数据库服务器的压力

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

 

 

 

 

                        

 

以上是关于FluentAPI深入的主要内容,如果未能解决你的问题,请参考以下文章

在不修改实体类(注释)或数据上下文(使用 fluentapi)的情况下禁用标识(自动递增)

EF CodeFirst系列---FluentApi

FluentAPI详细用法

深入理解DOM节点类型第四篇——文档片段节点DocumentFragment

实体框架代码优先 - Fluent Api 与数据注释的优缺点 [关闭]

EF6 FluentAPI,0:1 单向