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

        static void Main(string[] args)
{
using (TestDbContext ctx = new TestDbContext())
{ Person p = new Person
{
Name = "chenwwwwwwwwwwwwwwwwwwwwww",
Age=,
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();
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 = ,
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 =
};
Student s2 = new Student()
{
Name = "小王",
Age =
};
Student s3 = new Student()
{
Name = "小章",
Age =
};
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);
}
}

FluentAPI深入的更多相关文章

  1. EF CodeFirst系列(5)---FluentApi

    FluentApi总结 1.FluentApi简介 EF中的FluentApi作用是通过配置领域类来覆盖默认的约定.在EF中,我们通过DbModelBuilder类来使用FluentApi,它的功能比 ...

  2. EF CodeFirst系列(7)---FluentApi配置存储过程

    FluentApi配置存储过程 1.EF自动生成存储过程 EF6的CodeFirst开发模式支持给实体的CUD操作配置存储过程,当我们执行SaveChanges()方法时EF不在生成INSERT,UP ...

  3. EF CodeFirst系列(8)--- FluentApi配置单个实体

    我们已经知道了在OnModelCreating()方法中可以通过FluentApi对所有的实体类进行配置,然而当实体类很多时,我们把所有的配置都放在OnModelCreating()方法中很难维护.E ...

  4. Entity Framework(三)---FluentAPI和增删查改

    一.FluentAPI: 1.基本配置: namespace ConsoleApp14.ModelConfig { public class PersonConfig: EntityTypeConfi ...

  5. FluentAPI关系映射配置

    都有哪几种关系? 1vs多,多vs多 1. 概念or关系映射相关方法: 1) 基本套路:this.Has***(o=>o.AAA).With***() 当前这个表和AAA属性的表关系是Has定义 ...

  6. FluentAPI配置

    基本 EF 配置只要配置实体类和表.字段的对应关系.表间关联关系即可. 如何利用 EF的高级配置,达到更多效果:如果数据错误(比如字段不能为空.字符串超长等),会在 EF 层就会报错,而不会被提交给数 ...

  7. 用EFCore的 FluentAPI 方式生成MySql 带注释的数据库表结构

    采用的是net Core 3.1框架下的 的WebAPI项目. 1.  创建ASP.NET Core Web项目  2. 添加NuGet引用包,包如下 Microsoft.EntityFramewor ...

  8. Entity Fremework以及Fluentapi学习

    一.Entity Framework的入门  我这里采用的方式是数据库自己建立  然后模型类自己建立 数据库上下文类自己建立的方式 目的在于弄懂原理 其他的数据库优先等方式这里就不写了  教程有很多. ...

  9. 我画着图,FluentAPI 她自己就生成了

    在 Newbe.ObjectVistor 0.3 版本中我们非常兴奋的引入了一个紧张刺激的新特性:使用状态图来生成任意给定的 FluentAPI 设计. 开篇摘要 在非常多优秀的框架中都存在一部分 F ...

  10. EF FluentAPI映射一对多 关系时候报错

    提示很明显,不可为空的外键为空了,但是 问题是,我只是初始化 关系映射而已:见代码 public ColumnsCategoryMapConfiguration() { ToTable("C ...

随机推荐

  1. POJ-3041 Asteroids---二分图&最小覆盖点

    题目链接: https://vjudge.net/problem/POJ-3041 题目大意: 给一个N*N的矩阵,有些格子有障碍,要求我们消除这些障碍,问每次消除一行或一列的障碍, 最少要几次. 解 ...

  2. eclipse使用maven install 命令,生成war包中没有jsp/js/css的解决方法

    在pom.xml文件中添加如下11行代码就可以了. <build> <plugins> <plugin> <groupId>org.apache.mav ...

  3. 2017.9.27 JavaWeb 属性的设置和获取

    3.4.3新属性的设置和获取 对于getpParamter方法是通过参数传递获得数据, 设置数据的方法格式: void  request.setAttribute("key",Ob ...

  4. 字符串缓冲区StringBuffer类,正则表达式

    StringBuffer类 StringBuffer又称为可变字符序列,它是一个类似于 String 的字符串缓冲区,通过某些方法调用可以改变该序列的长度和内容.它是一个容器,容器中可以装很多字符串. ...

  5. LeetCode(Add Two Numbers)

    一.题目要求 You are given two non-empty linked lists representing two non-negative integers. The digits a ...

  6. checkboxlist如何配置数据源?

    在做项目中,通常checkboxlist中的checkitems不是固定的,需要绑定可变的数据源,把数据添加到list集合中,代码如下 DataSet myData = new DataSet(); ...

  7. (排班表三)导出列名不固定的Grid表格到Excel

    将班表信息导出Excel表格保存到本地 要求:文档名称为[XXXX]年X月值班表 文档显示的效果: 实现代码: //导出Excel值班表 private void btn_export_1_Click ...

  8. input宽度超出

    设置样式:style=“width:100%”;即可

  9. MySQL5.6基于MHA方式高可用搭建

    master 10.205.22.185 #MHA node slave1 10.205.22.186  #MHA node+MHA manager slave2 10.205.22.187  #MH ...

  10. MySQL中使用group_concat()函数数据被截取(有默认长度限制),谨慎!

    最近在工作中遇到一个问题: 我们系统的一些逻辑处理是用存储过程实现的,但是有一天客服反馈说订单下单失败,查了下单牵扯到的产品基础资源,没有问题. 下单的存储过程中有这样两句代码: ; ; ; 执行存储 ...