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. andriod给ListView中的TextView增加跑马灯效果

    正常情况下跑马灯效果只需要在TextView中添加android:ellipsize="marquee" android:singleLine="true" a ...

  2. HttpServletRequest request 获取form参数的两种方式

    @RequestMapping(value="/pay",method = RequestMethod.POST) public String buildRequest(HttpS ...

  3. ajaxfileup.js

    <img id="tinyPic" class="user-icon" :src="headPortrait"><inpu ...

  4. JavaScript 十行原生代码实现复制内容到剪贴板

    十行原生代码,不引入任何 JS 库,目前大部分浏览器与移动平台都可兼容. function copyToClipboard(value, callback) { var textarea = docu ...

  5. Python 初始—(字符编码解码)

    字符编码之间的编码转换则需要通过Unicode 进行转换,那么需要一个编码和解码实现与Unicode进行关联转换 例如utf-8转gbk utf-8----decode----->Unicode ...

  6. centos7部署harbor

    官网 https://github.com/goharbor/harbor 1.升级系统内核 rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrep ...

  7. VMware运行时“内部错误”的解决方法

    解决方法:打开虚拟机实体目录,如下:发现有两个虚拟机配置文件,一个文件大小为4KB,另一个为空.现在虚拟机默认使用为空的配置文件了. 将大小为空的虚拟机配置文件删除掉,然后将另一个配置文件重名命. 接 ...

  8. java @override 全部报错

    问.java @override 全部报错 答: 错误:在 eclipse 的新工作空间开发项目时,出现大面积方法编译错误.鼠标放在方法名上后显示让我们去掉 @override 注解 原因: @Ove ...

  9. SQL_server_2008_r2和visual studio 2010旗舰版的安装(2013-01-16-bd 写的日志迁移

    (以下操作是在Oracle VM virtualBox虚拟机中操作的,其实VMware Workstation 9虚拟机也挺不错的,不过用了很久的vmware想换个虚拟机用用 就暂时用Oracle V ...

  10. JZOJ 3534. 【NOIP2013提高组day1】货车运输

    Description A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路.每一条道路对车辆都有重量限制,简称限重.现在有 q 辆货车在运输货物,司机们想知道每辆车在不超过车辆限重的 ...