学习EntityFramework,实现分层架构

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);
        }
    }
}

到此结束。

  • 5
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值