Entity Framework 6 Code First系列1: 实体类1:1配置
来源:互联网 发布:网络协议实践教程笔记 编辑:程序博客网 时间:2024/05/23 20:48
从4.1版本开始,EF开始支持Code First模式,值得注意的是Code First不是和DataBase First或Model First平级的概念,而是和EDM平级的概念。使用Code First不再需要EDM来维护实体与数据库之间的映射关系,这个映射完全通过代码来完成,并在程序开始运行时在内存中建立一个映射模型,这也就是Code First这个名称中Code的含义。
随着Code First一起出现的是DbContext和DbSet类绝对可以称得上EF的核心功能,提供了与数据库通信,管理内存中实体的重要功能。
Entity Framework Profire
在正式介绍EF之前,首先介绍一款监听EF生成SQL语句文本的第三方软件Entity Framework Profire(收费版:但一个邮箱可试用一个月)。通过Entity Framework Profire,我们可以十分方便监听EF底层生成SQL语句的格式。
安装之后,在Global.asax全局配置文件中添加初始化语句:
App_Start.EntityFrameworkProfilerBootstrapper.PreStart();
下面是使用EntityFrameworkProfiler监听到的SQL语句;
映射
通过Code First来实现实体映射模型有两种方式 Data Annnotation 和 Fluent API。
Data Annotation需要在实体类的属性上以Attribute的方式表示主键、外键等映射信息。这种方式不符合解耦合的要求一般不建议使用
第二种方式就是要重点介绍的Fluent API。Fluent API的配置方式将实体类与映射配置进行解耦合,有利于项目的扩展和维护。Fluent API方式中的核心对象是DbModelBuilder。
重写DbContext的OnModelCreating(DbModelBuilder modelBuilder)方法,使用反射扫描程序集中所有继承自EntityTypeConfiguration<>的Map类,一次性添加到modelBuilder.Configurations集合中。
数据库上下文(继承自DbContext)
public class EFDbContext : DbContext { public EFDbContext() : base("DsUserCenterSQLConnection") { } public DbSet<Role> RoleList { get; set; } public DbSet<Menu> MenuList { get; set; } protected override void OnModelCreating(DbModelBuilder modelBuilder) { var typesToRegister =Assembly.GetExecutingAssembly().GetTypes() .Where(type => !String.IsNullOrEmpty(type.Namespace)) .Where(type => type.BaseType != null && type.BaseType.IsGenericType && type.BaseType.GetGenericTypeDefinition() == typeof(EntityTypeConfiguration<>)); foreach (var type in typesToRegister) { dynamic configurationInstance = Activator.CreateInstance(type); modelBuilder.Configurations.Add(configurationInstance); } base.OnModelCreating(modelBuilder); } }
这样,OnModelCreating就大大简化,并且一劳永逸的是,以后添加新的实体映射只需要添加新的继承自EntityTypeConfiguration<>的XXXMap 类而不需要修改 OnModelCreating 方法。
1:1单向映射(OperaterInfo-DepartmentInfo)
假设一个部门只有一个操作员,由于在数据库T_OperaterInfo表的字段DepartmentId并没有设置为外键,可将1:1通过1:N关联来实现
实体类OperaterInfo
public class OperaterInfo { public int Id { get; set; } /// <summary> /// 名字 /// </summary> public string Name { get; set; } /// <summary> /// 身份证号码 /// </summary> public string IDCard { get; set; } /// <summary> /// 手机号码 /// </summary> public string Phone { get; set; } /// <summary> /// 归属部门 /// </summary> public int? DepartmentId { get; set; } /// <summary> /// 导航属性-关联部门信息 /// </summary> public virtual DepartmentInfo DepartmentInfo { get; set; } }
配置类OperaterInfoMap
public class OperaterInfoMap : EntityTypeConfiguration<OperaterInfo> { public OperaterInfoMap() { ToTable("T_OperaterInfo"); HasKey(o => o.Id); HasOptional(o => o.DepartmentInfo).WithMany().HasForeignKey(s => s.DepartmentId); } }
实体类DepartmentInfo
public class DepartmentInfo { public int Id { get; set; } /// <summary> /// 部门名称 /// </summary> public string DeptName { get; set; } }
配置类DepartmentInfoMap
public class DepartmentInfoMap:EntityTypeConfiguration<DepartmentInfo> { public DepartmentInfoMap() { ToTable("T_DepartmentInfo"); HasKey(dept=>dept.Id); } }
控制台测试程序
class Program { static void Main(string[] args) { //初始化EntityFrameworkProfire App_Start.EntityFrameworkProfilerBootstrapper.PreStart(); using (var dbContext = new EFDbContext()) { //Include实现立即加载机制 var operaterList = dbContext.OperaterInfoList.Include("DepartmentInfo").ToList(); foreach (var opt in operaterList) { Console.WriteLine(string.Format("{0}:{1}",opt.Name,opt.DepartmentInfo.DeptName)); } } Console.ReadLine(); } }
执行结果
Profile监听到的结果就是上面的示例结果
然后我们修改上面的测试程序,将 Include(“DepartmentInfo”) 去掉,可发现控制台的执行结果并没有改变.
//Include实现立即加载机制//var operaterList = dbContext.OperaterInfoList.Include("DepartmentInfo").ToList();var operaterList = dbContext.OperaterInfoList.ToList();
查看Profile的监听结果如下:
EF框架:延迟加载与立即加载
注意到 OperatorInfo 类中有一个导航属性DepartmentInfo(使用 virtual 修饰符修饰)
/// <summary>/// 导航属性-关联部门信息/// </summary>public virtual DepartmentInfo DepartmentInfo { get; set; }
延迟加载可以理解为按需加载,EF并不会立即执行SQL加载数据,只有在执行ToList()、FirstOrDefault()方法时才会去查询数据库加载数据,但是延迟加载更多情况下是针对实体之间的关联属性(导航属性)。
如上例:当我们去查询OperatorInfo的时候,EF默认不会关联查询导航属性DepartmentInfo信息;只有在我们需要DepartmentInfo时才会去查询数据库找出对应的DepartmentInfo。这时就会产生数据库查询的“N+1”问题,如此频繁的查询数据库将会导致数据库压力激增,对于服务器内存的消耗十分可怕,影响程序的响应速度。
EF也允许我们通过编程的方式(.Include(“DepartmentInfo”))显式指定立即加载,在查询OperatorInfo时通过关联查询同时加载出DepartmentInfo。
在具体的编程环境中,我们要根据实际情况去决定使用“延迟加载”或“立即加载”,这对于EF框架的查询优化十分有必要。
在此特别感谢 博客园hystar 的 Entity Framework教程(第二版) ,拜读这边文章之后受益匪浅!
- Entity Framework 6 Code First系列1: 实体类1:1配置
- Entity Framework 6 Code First系列2: 实体类1:N配置
- Entity Framework 6 Code First系列3: 实体类M:N配置
- Code First :使用Entity. Framework编程(1)
- Entity Framework Code First 学习日记(1)
- Entity Framework Code First映射配置
- Entity Framework Code first
- Entity Framework Code First实体关联数据加载
- Entity Framework Code First添加修改及删除单独实体
- Entity Framework Code First实体对象变动跟踪
- Entity Framework 5.0系列之Code First数据库迁移
- Entity Framework 5.0系列之自动生成Code First代码
- Entity Framework 5.0系列之Code First数据库迁移
- Entity Framework 5.0系列之自动生成Code First代码
- Entity Framework 5.0系列之自动生成Code First代码
- Entity Framework 5.0系列之Code First数据库迁移
- Entity Framework 5.0系列之自动生成Code First代码
- Entity Framework 5.0系列之Code First数据库迁移
- Kotlin-委托
- Android Edittext限制输入小数位数
- c#知识点总结
- PostgreSQL 优化器的初步分析:query_planner()
- redis开机自启动
- Entity Framework 6 Code First系列1: 实体类1:1配置
- eclipse 创建 maven 项目
- redis开机自启动
- CSDN登录成功后跳转失败问题
- Oracle-11g学习6 - 11g 安装
- 12 个轻量级的 JavaScript 库
- 机器人操作系统ROS Indigo 入门学习(16)——记录和重放数据
- phpcms---form类的使用
- ASCII码排序