ORM:对象关系映射,为了解决面向对象与关系数据库存在的互补匹配的现象的技术.
O:表示内存中的对象
R:表示关系型数据库
M:表示映射逻辑关系
ORM的优劣势
优势
1.缩短编码时间,减少对Model的编码
2.支持多种数据库,提高程序扩展性
3.动态数据映射,数据表结构发生改变时,减少相关代码修改
劣势
1.性能,处理大量数据会消耗大量内存,严重影响性能
EF体系结构
主要包括EDM MetaData(核心)、Entity Client、Object Services、ADO .NET Provider
EDM:实体数据模型,它能将关系数据库模型映射为实体数据模型
CSDL:概念模型,对应实体类
SSDL:负责与数据库管理系统中的数据表做实体对应,表、列、关系等数据库存在的概念
MSL:负责将上层的概念层结构与下层的存储体结构中的成员相结合。
Entity Client:类似ADO.NET中的数据库操作类,主要用于操作EDM.
Object Service:EF提供的一系列操作业务对象的API,这些API需要依赖于Entity Client实现对数据库的访问
ADO.NET Provider:EF架构中,负责对具体数据库访问的只有Data Provider,Microsoft默认实现了对SQL server的ADO.NET Provider。
创建EF
添加实体数据模型(ADO.NET实体数据模型),选择相对于的数据表(分别为数据库优先,代码优先(推荐),模型优先)
认识EDMX文件
SSDL(存储层)、CSDL(概念层)、C-S mapping(对应层)
实体文件
导航属性并且使用virtual修饰,表示可以"懒加载",表示对象和对象之间的关系
- public class Sys_Attendance:Base
- {
- public int Sys_PersonId { get; set; }
- /// <summary>
- /// 打卡情况
- /// </summary>
- public string State { get; set; }
- public virtual Sys_Person Sys_Person { get; set; } //virtual懒加载 导航属性
- }
数据上下文
维护受业务影响的对象列表,负责管理对象的增、删、改、查操作,以及相应的事务及并发问题。
- public class OADbConText:DbContext
- {
- public OADbConText() : base("AoXiang") //链接字符串
- {
- Configuration.ProxyCreationEnabled = false;//可以进行EF循环引用
- }
- protected override void OnModelCreating(DbModelBuilder modelBuilder)
- {
- base.OnModelCreating(modelBuilder);
- modelBuilder.Configurations.AddFromAssembly(Assembly.GetExecutingAssembly()); //导入当前文件夹中全部的对表的配置
- modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>(); //取消级联
- modelBuilder.Conventions.Remove<ManyToManyCascadeDeleteConvention>();
- }
- }
导航属性
表示实体和另一个实体之间的关系
延迟加载
又称为"懒加载",只有每次调用子实体的时候,才去查询数据库,主表在加载的时候,不去查询外键所在的从表
实现延迟加载需要满足二个条件
1.类是public且不能为Sealed
2.导航属性需要标记virtual
关闭延迟加载:db.Configuration.LazyLoadingEnabled=false 关闭延迟加载后,查询主表数据时候,主表中的从表实体为null
贪婪加载
又名立即加载和预加载
查询主表的时候通过Include()方法一次性将数据查询出来,在调用从表数据的时候,从换成中读取,无须查询数据库
使用Code First(代码优先)
POCO:Plain old C# Object 表示 一堆普通的类和属性.
步骤
1.引用:EntityForamework 方式一:通过NuGet 方式二:通过Install-package EntityForamework(默认下载最新稳定版)
2.创建DbContext上下文(实现增删改查)
- //先创建POCO 一堆干净的普通类,没有约束特性
- public class Grade:Base
- {
- public int GradeId { get; set; }
- public string GradeName{ get; set; }
- //public virtual Sys_Person Sys_Person { get; set; } //virtual懒加载 导航属性
- }
-
-
-
-
-
- public class OADbConText:DbContext
- {
- public OADbConText() : base("AoXiang") //链接字符串
- {
- Configuration.ProxyCreationEnabled = false;//可以进行EF循环引用
- }
- protected override void OnModelCreating(DbModelBuilder modelBuilder)
- {
- base.OnModelCreating(modelBuilder);
- modelBuilder.Configurations.AddFromAssembly(Assembly.GetExecutingAssembly()); //导入当前文件夹中全部的对表的配置
- modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>(); //取消级联
- modelBuilder.Conventions.Remove<ManyToManyCascadeDeleteConvention>();
- }
- public virtual DbSet<Grade> Grade { get; set; } //virtual懒加载
- }
-
-
- static void Main(string[] args)
- {
- using (OADbConText entities = new OADbConText())
- {
- //实现添加
- Grade GradeInfo = new Grade()
- {
- GradeName = "s8"
- };
- entities.Grade.Add(GradeInfo);
- if (entities.SaveChanges() > 0)
- Console.WriteLine("数据添加成功!");
- }
- //删除操作
- using (OADbConText entitys = new OADbConText())
- { //实现思路先通过Id获取对象,然后进行删除
- Grade GradeInfo = entitys.Grade.FirstOrDefault(s => s.GradeId == 7);
- if (GradeInfo != null)
- entitys.Grade.Remove(GradeInfo);
- //SaveChanges获取受影响行数
- if (entitys.SaveChanges() > 0)
- Console.WriteLine("删除成功!");
- }
- //实现修改
- using (OADbConText entitys = new OADbConText())
- {
- Grade GradeInfo = entitys.Grade.FirstOrDefault(s => s.GradeId == 8);
- if (GradeInfo != null)
- GradeInfo.GradeName = "s10";
- if (entitys.SaveChanges() > 0)
- Console.WriteLine("修改成功!");
- }
- //实现查询(查询单个使用FirstOrDefault)
- using (OADbConText entity = new OADbConText())
- {
- //实现查询
- IQueryable<Grade> GradeInfo = entity.Grade.Where(s => s.GradeName == "s8");
- foreach (var item in GradeInfo)
- {
- Console.WriteLine(item.GradeId);
- }
- }
-
- }
Code First映射规则
1.表中列和类中字段名称一样
2.主键名称为Id,数据类型为Int或者GUID类型会把设置为标识列
3.字符串映射到数据库时数据类型为nvarchar(Max),并且允许为空
4.bool类型映射为bit类型,不允许为空
5.外键约定
会找到类名Id或者字段Id设置为外键,但是需要注意如果没有找到,EF会自己生成一个外键
一对多:在多方设置外键和导航属性
修改映射规则
数据注解(耦合度太高,不适合大项目开发)
特性 | 说明 |
Key | 主键 |
Required | 非空 |
MinLength/MaxLength | 最大长度和最小长度,默认数据类型nvarchar |
StringLength | 设置string类型的长度,默认nvarchar |
ConcurrencyCheck | 并发检查,执行update语句时,会坚持并发性(乐观锁) |
Table | 给数据库表起别名 |
Column | 给表中列起别名 |
ForeignKey | 设置外键 |
NotMapped | 列不映射到数据库,或者只设置get属性或设置set属性 |
Fluent API(推荐) 链式操作
Fluent API方法 | 说明 |
HasMany() | 一对多或者多对多 |
HasOptional() | 一个可选的关系,数据库生成一个可空的外键 |
HasRequired() | 一个必有的关系,数据库生成一个不能为空的外键 |
Map() | 设置一些优先的配置 |
ToTable() | 为实体设置表名 |
Ignore() | 实体的属性不映射到数据库 |
IsRequired() | 属性不能为空 |
HasColumnType() | 配置数据库中对应列的数据类型 |
HasColumnName() | 配置数据库中对应列的列名 |
每次当数据表结构发生改变的时候,会出现一系列问题二种解决方式
EF的Database.Setlnitializer参数(了解即可,不推荐使用) 使用方式:在数据上下文 构造函数中使用
数据库不存在时重新创建数据库
Database.Selnitializer<DbContest名称>(new CreateDatabaselfNotExists<DbContest名称>())
每次启动时创建数据库
Database.Selnitializer<DbContest名称>(new DropCreateDatabaseAlways<DbContest名称>())
模型更改时重新创建数据库
Database.Setlnitializer<DbContest名称>(new Create DatabaselfModelchanges<DbContest名称>())
从不创建数据库
Database.Setlnitializer<DbContest名称>(null)
第二种,数据迁移(注意EF的版本,推荐使用) 使用方式:在程序包管理台控制器使用,只要要修改默认项目,直接输入代码就行
启动:Enable-Migrations
创建:Add-Migration 名称
执行:Update-Database [参数] 可升级,可回滚,填写参数即可
删除:remove-migration 最近的一个迁移
生成迁移脚本:Script-migration 可以生成中间 D F之间版本
优化EF
影响EF性能的因素
1.复杂的对象管理机制(内部机制管理和跟踪对象状态)
2.高度封装的执行机制(表达式解析为SQL语句,没有直接执行SQL语句效果快)
3.低效的SQL语句(基于模板生成,处理复杂业务性能下滑)
状态管理
通过Entry()进行获取模型状态
方法或属性 | 说明 |
CurrentValues | 获取由此对象表示的跟踪实体的当前属性值 |
OriginalValues | 获取由此对象表示的跟踪实体的原始属性值 |
State(枚举) | 获取或设置实体的状态(EF五态) Detached:表示对象存在,没有被跟踪 Unchanged:表示对象尚未经过更改 Added:表示对象为新对象,并且已添加到对象上下文 Deleted:对象已从对象上下文中删除 Modified:表示对象的一个标量属性已修改 使用语法: 上下文名称.Entry(对象名称).State=EntityState.状态 |
Reload | 从数据库重新加载对象的值 |
Attach()
将给定实体以Unchanged的状态附加到上下文中 注意:不要进行添加操作
AsNoTracking()
指定数据上下文不对查询结构的对象进行状态管理(只进行展示时)
调用这个方法获取的数据对象,状态为Detached不进行跟踪
执行原始SQL语句
ExecuteSqlCommand()执行增删改方法
SqlQuery<T>(SQL)进行查询 返回是一个集合 T代表返回类型
EF实现数据访问的底层代码(三层架构DAL,业务逻辑层只需调用DAL层实现业务逻辑即可)
- using Stu.Models;
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Threading.Tasks;
- using System.Linq.Expressions;
- using System.Data.Entity;
-
- namespace Stu.DAL
- {
- public class BaseService<T> where T:Base,new()
- {
- private MyDbConText db = new MyDbConText();
- public int Add(T t) //添加
- {
- db.Set<T>().Add(t);
- return db.SaveChanges();
- }
- public async Task<int> AddAsync(T t) //异步添加
- {
- db.Set<T>().Add(t);
- return await db.SaveChangesAsync();
- }
- public int Delete(int Id) //删除
- {
- var Item = new T() { Id = Id };
- db.Entry(Item).State = System.Data.Entity.EntityState.Deleted;
- return db.SaveChanges();
- }
- public async Task<int> DeleteAsync(int Id) //异步删除
- {
- var Item = new T() { Id = Id };
- db.Entry(Item).State = System.Data.Entity.EntityState.Deleted;
- return await db.SaveChangesAsync();
- }
- public int Edit(T t) //修改
- {
- db.Entry(t).State = System.Data.Entity.EntityState.Modified;
- return db.SaveChanges();
- }
- public async Task<int> EditAsync(T t) //异步修改
- {
- db.Entry(t).State = System.Data.Entity.EntityState.Modified;
- return await db.SaveChangesAsync();
- }
- public IQueryable<T> GetList() //返回全部数据
- {
- return db.Set<T>();
- }
- public T GetAllById(int Id) //通过Id返回单个对象
- {
- return GetList().FirstOrDefault(e => e.Id==Id);
- }
- public async Task<T> GetAllByIdAsync(int Id) //异步
- {
- return await GetList().FirstOrDefaultAsync(e => e.Id == Id);
- }
- public int Edit(T obj, params string[] updateFields) //修改部分列
- {
- db.Set<T>().Attach(obj);
- foreach (var attr in typeof(T).GetProperties())
- {
- if (updateFields.Contains(attr.Name))
- {
- db.Entry(obj).Property(attr.Name).IsModified = true; // 设置属性被修改
- }
- }
- return db.SaveChanges();
- }
- public IQueryable<T> GetList(Expression<Func<T,bool>> Where) //返回全部带条件
- {
- return db.Set<T>().Where(Where);
- }
- public IQueryable<T> OrderBy<K>(Expression<Func<T,bool>> where,int PageIndex,int PageSize,out int Count,Expression<Func<T,K>> Orders,bool IsOrder) //实现分页
- {
- var Item = db.Set<T>().Where(a=>1==1);
- Item = where != null ? Item.Where(where):Item;
- Count = Item.Count();
- return (IsOrder ? Item.OrderBy(Orders) : Item.OrderByDescending(Orders)).Skip(PageSize * (PageIndex - 1)).Take(PageSize);
- }
- }
- }
到此结束。