entityframeworktutorial (EF 教程) EF Basics (EF基础)(翻译)

学习EF 找到这个网站:

http://www.entityframeworktutorial.net/

第一课, EF Basics (EF 基础)

如果你刚刚接触 EF, 建议你学习 EF基础知识,层层渐进

 目录:

1. 什么是 Entity Framework?

2. EF的基本流程 

3. EF如何运作?

4. EF架构

5. EF中的Context类

6. 什么是EF中的实体?

6.1  EF中实体的类型

6.2 EF中实体的状态

7. EF开发模式

8. EF中的持久化

什么是 Entity Framework?(What is Entity Framework?)

.net3.5 之前,开发人员经常需要 基于ADO.NET 或企业数据访问块进行编码,以便于从基础数据库读写应用数据。我们通常打开一个数据库连接,创建一个 DataSet 以从数据库获取数据或提交数据到数据库, 转换 DataSet 数据为 .Net对象或执行相反的操作来实现应用逻辑。这是一个非常繁琐并非常容易出错的过程。微软提供了一个叫做 EntityFramework 的框架来自动为你的应用程序完成这些数据库相关的操作。

EF 是微软提供的一个支持.Net应用程序的开源 ORM框架。它使开发人员不需要关注基础数据库的表和列的操作,而直接与类的域对象进行交互。使用EF, 开发人员可以在更高的抽象层处理这些数据,相对于传统数据库应用,可以用更少的代码来创建和维护数据库。

官方的定义: “Entity Framework is an object-relational mapper (O/RM) that enables .NET developers to work with a database using .NET objects. It eliminates the need for most of the data-access code that developers usually need to write.”

EF 是一个 对象-关系 的映射 (O/RM) ,它允许.Net 开发人员使用 .Net对象来操作数据库。它减少了开发人员需要写的大部分数据访问的需要。

下图显示了应用程序中的EF 框架

从上图来看,EF匹配业务逻辑和数据库之间的操作,它自动实现了保存业务逻辑对象的属性到数据库和从数据库检索数据并将其转为业务逻辑对象的过程。

实体框架的特点:

跨平台: EF的核心是一个跨平台的框架,它可以运行在Windows, Linux, Mac。

模型化: EF 基于POCO(一般clr对象,Plain Old CLR Object)创建了一个 EDM(实体数据模型, Entity Data Model), 它包含了不同同数据类型的 get/set 属性。EF使用这个实体数据模型来从数据库查询数据和保存对象到数据库。

支持查询: EF 允许我们使用LINQ查询 (c#, vb.net) 从基础数据库中检索数据。数据库引擎把这个LINQ查询的查询语句转换为数据库特定的查询语句 (如关系型数据库的SQL语句)。 EF 还允许我们直接使用SQL语句查询数据库。

更改跟踪: EF记录需要提交到数据库的实体(属性)的变更。

支持保存: 当应用程序调用 SaveChanges方法时, EF执行 Insert, Update, Delete命令来根据你的实体变化修改数据库。EF还提供了异步方法 SaveChangesasync() 方法来保存更改。

并发: EF默认使用开放式并发策略来避免当你从数据库提取数据后另一个用户对数据库进行更改。

事务: EF 当查询、保存数据时,自动使用事务管理。它还提供了自定义的事务管理选项。

缓存: EF 在数据库外使用一级缓存,所以,反复的查询总是从缓存返回数据而不是每次都去读取数据库。

内置规则: EF 遵守可配置化编程模式的规则,包含一系列可以自动应用在EF模式的默认规则。

允许配置: EF允许我们通过注释属性或Fluent API 来重载配置EF模型的默认规则。

迁移: EF 提供了一系列可直接在Nuget 包管理器控制台或命令行接口直接执行的的迁移命令来创建、管理基础数据库模式。

实体框架的最新版本

微软在2008年推出了EF 3.5。从那以后,它发布了许多版本。现在,有两个EF的最新版本: EF 6 和 EF Core。 下表列出了EF6和EF Core 的主要区别:

| EF 6 | EF Core | | √最早在2008年基于 .Net Framework 3.5SP1 发布 | √最早在2016年6月基于 .Net Core1.0 发布 | | √稳定并且有丰富的特性 | √比较新,正在发展中 | | √只支持windows平台 | √ Windows,Linux,OSX | | √支持 .Net 3.5 及以后的版本 | √ 支持.Net 4.5及以后的版本、.Net Core | | √ 开源 | √ 开源 |

EF6发布历史

| EF 版本 | 发布时间 | .Net 框架 | | EF 6 | 2013 | .Net 4.0和4.5 , VS 2012 | | EF 5 | 2012 | .Net 4.0 , VS 2012 | | EF 4.3 | 2011 | .Net 4.0 , VS 2012 | | EF 4.0 | 2010 | .Net 4.0 , VS 2010 | | EF 1.0 (或3.5) | 2008 | .Net 3.5 SP1 , VS 2008 |

EF Core发布历史

| EF Core 版本 | 发布时间 | .Net 框架 | | EF Core2.0 | 2017年8月 | .Net Core 2.0, VS2017 | | EF Core1.1 | 2016年11月 | .Net Core1.1 | | EF Core1.0 | 2016年6月 | .Net Core1.0 |

EF的基本流程 (Basic Workflow in Entity Framework)

在这里,您将学习EF的 CRUD 基础工作流

下图说明了基本的工作流程:

我们来分析一下上图的EF工作流程:

  1. 首先,你需要定义你的模型。定义模型包括定义你的域类,从DbContext类定义环境类,并定义配置。EF会在你的模型上执行CRUD操作。
  2. 插入数据,添加一个域对象到context,并调用SaveChanges()方法,EF 会构造行当的 INSERT命令,并在数据库中执行。
  3. 读取数据时,使用开发语言(c#/Vb.net)执行一个 LINQ-TO-Entities 查询,EF API 会将这个查询转换为关系型数据库的SQL查询并在数据库中执行。执行结果会被转换为域对象并在界面上显示。
  4. 编辑和删除数据,修改或从context 中删除对象后,调用 SaveChanges() 方法,EF API 会构建行当的UPDATE或DELETE 命令并在数据库中执行。

接下来,我们将看到EF如何工作。

EF如何运作?(How Entity Framework Works?)

本节,你会看到EF如何运作的概述。

EF API(包括 EF6和 EF Core)拥有映射域类(对象)到数据库,转换、执行LINQ查询为SQL语句,在实体的生命周期内跟踪变化,保存修改到数据库的能力。

实体数据模型

EF API的第一个任务是建立实体数据模型 (EDM)。 EDM是所有元数据的内存表示:概念模型、存储模型以及它们的映射。

概念模型: EF 根据你的域类和配置从域类、context类、默认规则建立概念模型。

存储模型: EF为底层数据库建立存储模型。如果是CodeFirst 模式,这将从概念模型生成。如果是DatabaseFirst模式,这将从数据库生成。

映射: EF 包含了概念模型到数据库(存储模型)的映射信息

EF 使用EDM执行CRUD操作。它使用EDM 来从LINQ-TO-Entities 构造 SQL查询,构造INSERT、UPDATE、DELETE命令,并将数据库查询结果转换为实体对象。

查询

对于关系型数据库, EF API 使用EDM将 LINQ-TO-Entities 查询转换为 SQL查询语句,同时将查询结果返回给实体对象。

存储

EF API 在SaveChanges() 方法被调用时基于实体的状态构造 INSERT、UPDATE、DELETE命令。修改记录包括实体的状态变更和对实体的操作的记录。

EF架构 (Entity Framework Architecture)

下图展示了EF的整体架构

我们来看看架构的各个组成部分:

EDM(实体数据模型): EDM由三部分组成: 概念模型、映射和存储模型。

概念模型:概念模型包含模型类及其关系。这将是独立于你的数据库表的设计。

存储模型:存储模型的数据库设计模型,包括表、视图、存储过程、以及它们之间的关系和主键。

映射: 映射包含概念模型是怎么映射到存储模型的。

Linq to Entities:Linq to Entities(L2E) 是一种针对对象模型的进行查询的查询语言。它返回在概念模型中定义的实体。在这里你可以使用LINQ技巧。

Entity SQL: Entity SQL 像Linq to Entities一样是另一种查询语言(从EF6)开始。但是它比L2E难一些,开发者需要单独学习。

对象服务: 对象服务是从数据库存取数据并返回的主要入口。对象服务主要负责物理化,及从 客户端数据提供器返回的实体转换为实体对象结构的过程。

实体的客户端数据提供器: 这一层主要负责将 Linq To Entities或Entity SQL 的查询转换为底层数据库可以理解的SQL语句。它主要与ADO.NET数据提供器通信,以给数据库发送或获取信息。

ADO.NET数据提供器: 这一层使用标准ADO.NET 与数据库进行通信

EF中的Context类 (Context Class in Entity Framework)

EF中,Context类一个是从DbContext派生的类。它在EF中是一个很重要的类,它代表了一个与数据库的连接。

以下的 SchoolContext 类是一个例子中的context类:

public SchoolContext : DbContext
{
    public SchoolContext() {}

    public DbSet<Student> Students {get; set;} public DbSet<StudentAddress> StudentAddresses{get;set;} public DbSet<Grade> Grades {get;set;} }

在上面的例子中, SchoolContext 派生自 DbContext,所以它是一个context类。它还包括一个Student的 DbSet, 一个StudentAddress的DbSet,一个Grade的DbSet。

context类用于查询或保存数据到数据库。它也被用来配置域类、数据库关系的映射、修改记录的设置、缓存、事务管理等。

EF6 ContextEF Core Context 中可以了解更多 context类

什么是EF中的实体?(What is an Entity in Entity Framework?)

EF中的实体是你的应用程序作用域中的一个类,context类包含它的一个DbSet 集合属性。EF API将每个实体映射为一张表,将实体的每个属性映射为表中的一列。

例如,下面是 Student,StudentAddress和 Grade类在学校这个实例中的应用。

public class Student
{
    public int StudentID { get; set; }
    public string StudentName { get; set; }
    public DateTime? DateOfBirth { get; set; }
    public byte[] Photo { get; set; }
    public decimal Height { get; set; }
    public float Weight { get; set; }

    public StudentAddress StudentAddress { get; set; }
    public Grade Grade {get; set; }
}

public partial class StudentAddress
{
    public int StudentID { get; set; }
    public string Address1 { get; set; }
    public string Address2 { get; set; }
    public string City { get; set; }
    public string State { get; set; }

    public Student Student { get; set; }
}

public class Grade
{
    public int GradeID { get; set; }
    public string GradeName { get; set; }
    public string Section { get; set; }

    public ICollection<Student> Students { get; set; }
}

当被包含在像下面的context类(从DbContext类派生)的DbSet属性中时,上面的3个类,就变成了实体。

public class SchoolContext : DbContext
{
    public SchoolContext()
    {

    }

    public DbSet<Student> Students { get; set; }
    public DbSet<StudentAddress> StudentAddresses { get; set; }
    public DbSet<Grade> Grades { get; set; }
}

在上面的 context类中,类型为DbSet的 Students, StudentAddresses和Grades属性被称为实体集。 Stuent, StudentAddress和Grade 都是实体(也称为实体类型)。

标量属性

原始类型的属性叫作标量属性。一个标量属性保存了真正的数据。一个标量属性映射为数据表的一列。

导航属性

导航属性反应了实体与另一个实体的关系。 有两种导航属性: 引用导航和集合导航

引用属性

如果一个实体包含一个类型为另一个实体的属性,则这个属性叫作引用导航属性。它代表的多重性为1。

集合导航属性

如果一个实体包括一个集合属性,这就是集合导航属性。它代表的多重性为 *。 用下图说明实体的属性:

EF中实体的类型 (Types of Entities in Entity Framework)

EF中有两种类型的实体: POCO实体和动态代理实体。

POCO实体 (传统CLR对象)

一个POCO实体是一个不依赖于任何特定框架基类的类。它像其他任何正常的.Net Clr类,这就是它为什么被称为”Plain Old CLR Object“。 POCO实体在EF 和 EF Core中都支持。 这些POCO实体(也被称为永久-无知对象)支持大多数与EDM生成的实体类型相同的查询、插入、更新、删除行为。下面是Student类的POCO实体实例:

public class Student
{
    public int StudentID { get; set; }
    public string StudentName { get; set; }
    public DateTime? DateOfBirth { get; set; }
    public byte[]  Photo { get; set; }
    public decimal Height { get; set; }
    public float Weight { get; set; }

    public StudentAddress StudentAddress { get; set; }
    public Grade Grade { get; set; }
}

动态代理实体(POCO Proxy)

动态代理是封装了一个POCO对象的运行时代理类。动态代理实体允许懒加载。

注意: 只有EF6支持动态代理实体,EF Core 2还不支持。

一个POCO对象要变成POCO代理实体,需要满足以下条件:

  1. POCO类必须声明为public。
  2. POCO类不能声明为sealed(vb.net中的 NotInheritable)。
  3. POCO类不能声明为abstract(vb.net中的MustInherit)。
  4. 每个导航属性必须声明为 public virtual。
  5. 每个集合属性必须是 ICollection。
  6. context的 ProxyCreationEnabled选项必须不是false(默认为true)。

下面的poco实体满足以上所有要求,所以是动态代理实体

public class Student
{
    public int StudentID { get; set; }
    public string StudentName { get; set; }
    public DateTime? DateOfBirth { get; set; }
    public byte[]  Photo { get; set; }
    public decimal Height { get; set; }
    public float Weight { get; set; }

    public virtual StudentAddress StudentAddress { get; set; }
    public virtual Grade Grade { get; set; }
}

注意: 默认情况下,每个实体都开启了动态代理,你可以通过设置context.Configuration.ProxyCreationEnabled = false; 禁止动态代理,如下面代码:

使用动态代理对像的 ObjectContext.GetObjectType() 来找到被封装的对象:

EF中实体的状态(Entity States in Entity Framework)

EF在每个实体的生命周期内,一直保存它的状态。每个实体,基于通过context类对它的操作,都有一个状态。实体的状态通过枚举类型System.Data.Entity.EntityState (EF Core中为 Microsoft.EntityFrameworkCore.EntityState)来表示:

  1. Added
  2. Modified
  3. Deleted
  4. Unchanged
  5. Detached

context 不仅在从数据库中检索时即时产生所有实体对象,并且跟踪实体的状态,保留实体属性修改记录。此功能称为更改跟踪。

实体的状态更改中,只有从 Unchanged到 Modified是 context类自动完成的。所有其他变化都必须正确地调用 DbContext和DbSet。(你会在EF6和EF Core)的部分学到这些。

EF API在调用SaveChanges方法被调用时建立并执行 Insert、Update、Delete命令。它为Added状态的实体执行插入命令,为Modified状态的实体执行Update操作,为Deleted状态的实体执行DELETE操作。context类不记录状态为 Detached状态的实体。下图说明了实体状态的意义:

因此,实体状态在实体框架中有很重要的作用。

EF开发模式(Development Approaches with Entity Framework)

有三种不同的模式可以在您的应用中使用EF框架

  1. Database First
  2. Code First
  3. ModelFirst

Db-First

在DbFirst时,你使用VS中的EDM向导或使用EF命令来从数据库生成context和实体。

EF6广泛地支持 DbFirst,访问 EF6 DbFirst章节来学习如何使用EF6 DbFirst方法开发。

EF Core对这种方法仅提供有限的支持。

Code-First

当你的应用程序还没有数据库时,使用CodeFirst模式。在CodeFirst模式中,需要先写实体类(域类)和上下文类,然后EF使用迁移命令从这些类创建数据库。 遵守领域驱动设计(DDD)原则的开发者喜欢先编写域类,然后生成需要的数据库来存放数据。

阅读 EF6 CodeFirst教程 章节来学习EF6 CodeFirst 开发。 阅读 EF Core 章节来学习 EF Core 中的CodeFirst开发。

Model-First

Model-First 模式中,先在VS的可视化设计器中创建实体、关系和继承层次,然后从视觉模型生成实体类、context类和数据库脚本。

EF6包含这种模式的有限支持。

EF Core不支持这种模式。

##选择您的应用程序开发方法

使用下面的流程图来决定在您的应用程序中正确的使用EF的方式:

根据上面的图,如果你的应用程序中已经有一个域类,那你可以使用CodeFirst模式,因为你可以从现有类创建一个数据库。如果你有一个数据库,那么你可以使用Database-First模式创建一个EDM。如果你没有数据库和类,并且喜欢在可视化设计器中设计你的数据库模型,那么使用ModelFirst 模式。

EF中的持久化(Persistence in Entity Framework)

EF中有持久化(保存)一个实体到数据库有两种场景: 连接时和断开时。

连接时

在连接数据库的情况下,使用context(派生自DbContext)类的同一个实例来检索和保存实体。它跟踪所有实体的生命周期。这种情况通常是在使用本地数据库或同一网络中的数据库的Windows应用程序中。

优点:

  • 快速执行。

  • context类跟踪记录所有实体,并且当实体发生变化时,自动给实体设置适合的状态。

缺点:

  • 只有context类还未翻译,数据库一直保持打开状态。
  • 需要占用较多资源。

断开连接时

在断开的情况下,使用context类的不同实例来实现读取和保存数据。一个context将在获取数据后被释放,创建一个新的实例来保存数据到数据库。

断开连接的情况比较复杂,context类不跟踪实体的实例,所以你必须在调用SaveChanges方法向数据库保存数据前对每个实体设置合适的状态。上图中,使用Context1 来执行一些查询,然后使用Context2 来执行创建、更新、删除操作。在这种情况下Context2不知道发生在实体上的操作。

这通常在Web应用程序和远程数据库访问的应用中使用。

 优点:

  •  相对于保持连接的情况,这种方法占用资源较少。
  •  没有打开数据库连接。

 缺点: -  每个实体在保存前都需要设置一个合适的状态。 -  执行速度比连接的情况差。

转载于:https://my.oschina.net/ytianxia6/blog/2246796

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值