FluentAPI深入
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深入的更多相关文章
- EF CodeFirst系列(5)---FluentApi
FluentApi总结 1.FluentApi简介 EF中的FluentApi作用是通过配置领域类来覆盖默认的约定.在EF中,我们通过DbModelBuilder类来使用FluentApi,它的功能比 ...
- EF CodeFirst系列(7)---FluentApi配置存储过程
FluentApi配置存储过程 1.EF自动生成存储过程 EF6的CodeFirst开发模式支持给实体的CUD操作配置存储过程,当我们执行SaveChanges()方法时EF不在生成INSERT,UP ...
- EF CodeFirst系列(8)--- FluentApi配置单个实体
我们已经知道了在OnModelCreating()方法中可以通过FluentApi对所有的实体类进行配置,然而当实体类很多时,我们把所有的配置都放在OnModelCreating()方法中很难维护.E ...
- Entity Framework(三)---FluentAPI和增删查改
一.FluentAPI: 1.基本配置: namespace ConsoleApp14.ModelConfig { public class PersonConfig: EntityTypeConfi ...
- FluentAPI关系映射配置
都有哪几种关系? 1vs多,多vs多 1. 概念or关系映射相关方法: 1) 基本套路:this.Has***(o=>o.AAA).With***() 当前这个表和AAA属性的表关系是Has定义 ...
- FluentAPI配置
基本 EF 配置只要配置实体类和表.字段的对应关系.表间关联关系即可. 如何利用 EF的高级配置,达到更多效果:如果数据错误(比如字段不能为空.字符串超长等),会在 EF 层就会报错,而不会被提交给数 ...
- 用EFCore的 FluentAPI 方式生成MySql 带注释的数据库表结构
采用的是net Core 3.1框架下的 的WebAPI项目. 1. 创建ASP.NET Core Web项目 2. 添加NuGet引用包,包如下 Microsoft.EntityFramewor ...
- Entity Fremework以及Fluentapi学习
一.Entity Framework的入门 我这里采用的方式是数据库自己建立 然后模型类自己建立 数据库上下文类自己建立的方式 目的在于弄懂原理 其他的数据库优先等方式这里就不写了 教程有很多. ...
- 我画着图,FluentAPI 她自己就生成了
在 Newbe.ObjectVistor 0.3 版本中我们非常兴奋的引入了一个紧张刺激的新特性:使用状态图来生成任意给定的 FluentAPI 设计. 开篇摘要 在非常多优秀的框架中都存在一部分 F ...
- EF FluentAPI映射一对多 关系时候报错
提示很明显,不可为空的外键为空了,但是 问题是,我只是初始化 关系映射而已:见代码 public ColumnsCategoryMapConfiguration() { ToTable("C ...
随机推荐
- 【BZOJ4487】[JSOI2015] 染色问题(高维容斥)
点此看题面 大致题意: 有一个\(n*m\)的矩形,先让你用\(C\)种颜色给它染色.每个格子可染色可不染色,但要求每行每列至少有一个小方格被染色,且每种颜色至少出现一次.求方案数. 高维容斥 显然题 ...
- python 造轮子(一)——序列与字典
虽然说造轮子很少用了,什么底层东西很少写,但是还是很想学扎实,还是好多东西还是的会,没有底层的支持,比较高级的库学起来还是很困难的. 序列的普遍用法: #-*-coding:utf8-*- #索引 l ...
- maven简单了解,没有Maven和使用Maven的区别
Maven提供了开发人员构建一个完整的生命周期框架.开发团队可以自动完成项目的基础工具建设,Maven使用标准的目录结构和默认构建生命周期.Maven让开发人员的工作更轻松,同时创建报表,检查,构建和 ...
- js另类值交换
当我们有a.b两个值,想要交换,通常是要声明第三个变量,但是我最近看到这样一种不用声明第三个变量的处理方法: var a=1,b=2; a=[b,b=a][0]; 其实还是在内存中开出了一个新的空间( ...
- 前端HTML之表单
1.列表标签 1.1无序列表<ul>,当中每一层都是<li> <ul> <li>张三</li> <li>李四</li ...
- 2.vue脚手架项目配置
1.更改网站名: index.html <!DOCTYPE html> <html> <head> <meta charset="utf-8&quo ...
- 当Java遇见了Html--Servlet篇
###一.什么是servlet servlet是在服务器上运行的小程序.一个servlet就是一个 java类,并且通过"请求-响应"编程模型来访问的这个驻留在服务器内存里的程序. ...
- 详解LinkedHashMap如何保证元素迭代的顺序
大多数情况下,只要不涉及线程安全问题,Map基本都可以使用HashMap,不过HashMap有一个问题,就是迭代HashMap的顺序并不是HashMap放置的顺序,也就是无序.HashMap的这一缺点 ...
- 内置函数SQLCODE和SQLERRM的使用
由于ORACLE的错信息最大长度是512字节,为了得到完整的错误提示信息,我们可用 SQLERRM 和 SUBSTR 函数一起得到错误提示信息,方便进行错误,特别是如果WHEN OTHERS异常处理器 ...
- ios数据持久化--CoreData框架的介绍和使用
1.Core Data 是数据持久化存储的最佳方式 2.数据最终的存储类型可以是:SQLite数据库,XML,二进制,内存里,或自定义数据类型 在Mac OS X 10.5Leopard及以后的版本中 ...