zoukankan      html  css  js  c++  java
  • 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);
                    }
                }

                            

  • 相关阅读:
    Android进阶之关闭所有activty
    弹出窗口插件欣赏
    关于之前放在google 的资源不能下载的解决方案
    图片垂直居中的使用技巧
    关于采用业务用例视图来展示、归纳、整理业务用例的三点指导原则
    操作系统引导的那点事
    可视化拾色器
    AE中删除属性字段
    AE中添加属性字段
    vs2005c#中用户组件在工具箱中不能自动出现的解决办法
  • 原文地址:https://www.cnblogs.com/fuyouchen/p/9413943.html
Copyright © 2011-2022 走看看