【转】Entity Framework技术导游系列开篇与热身

转自:http://blog.csdn.net/bitfan/article/details/12779517

Entity Framework走马观花 之

把握全局

=========================================

这是一个系列文章

上一篇《Entity Framework技术导游系列开篇与热身

=========================================

在深入学习某项技术之前,应该努力形成对此技术的总体印象,并了解其基本原理,本文的目的就在于此。

一、理解EF数据模型

EF本质上是一个ORM框架,它需要把对象映射到底层数据库中的表,为此,它使用了三个模型来描述这种映射关系。

(1)概念模型(Conceptual Model):主要体现为一组可以被应用程序直接使用的类。这些类也是我们在程序中直接使用的类,通常称之为“实体(Entity)”

(2)存储模型(Storage Model):主要体现为一组与底层数据存储介质(比如数据库系统)直接对应的类。

(3)概念-存储模型映射(Conceptual- Storage Mapping),解决“概念模型”中的类如何与“存储模型”中的类相互对应的问题。

(2)和(3)中的类型由EF内部使用,在实际开发中通常触及不到。

所有这三种模型都集中放在名为edmx文件中,以XML方式表达。

VisualStudio提供了一个向导,完成从现有数据库到EF数据模型间的映射转换工作:

当此向导完成之后,EF成功地在数据库与程序中使用的对象之间建立了以下对应关系:


关系数据库的世界


数据库应用程序的世界


数据库


DbContext类



DbContext中的DbSet<实体类名>


表间的关联


实体类之间的关联


表中的字段


实体类的公有属性


表中的单条记录


单个实体类的对象


视图


DbContext中的DbSet<视图名称>


存储过程


DbContext中的公有方法

可以在Visual Studio 的模型浏览面板中看到EF数据模型的概念模型和存储模型,如果直接以xml格式打开.edmx文件,可以看到“原汁原味”的全部三大数据模型。

Visual

Studio提供的EF向导不仅生成了上述三大数据模型,还使用T4代码模板(其文件扩展名为.tt)直接生成了相应实体类,还有一个派生自
DbContext的子类,在其中包容了所有实体集合属性和导入的存储过程等数据库元素。这一DbContext子类是我们使用EF开发程序的核心类型。

在解决方案资源管理器中双击“edmx”文件将打开EF设计器,这是一个很强悍的工具,几乎所有的调整数据映射关系的工作都可以使用它来完成。

如果基于Database First或Model First方式开发,那么EF设计器是天天要打交道的东西。其操作方式很简单:右击设计器,从弹出菜单中选择相应命令

EF设计器提供的各种命令和具体使用方法有很多资料介绍,在此就不废话了。

二、使用EF访问数据库的基本方式

EF中可以使用以下四种方式访问数据库:

Entity SQL是专门为EF设计的一种查询语言,非常类似于通用的关系型数据库查询语言SQL,但它返回的数据都是在EF“概念模型”中所定义的,而非数据库中数据的“真实模样”。

LINQ to Entities可以看成是LINQ  to
 Objects的一个“变种”,通过LINQ来查询EF数据模型。它在底层使用“对象服务(Object
services)”来完成其功能。对象服务是一组用于查询实体数据模型的类,它可以将这些查询结果转换为强类型的CLR对象。

不管是使用Entity SQL还是LINQ to Entities,最终都是依赖“Entity Client”来完成其工作的。

Entity
Client包容一组类,比如EntityConnection、EntityDataReader等,与ADO.NET对象模型非常类似,其功能也类
似。Entity Client会将对数据的CRUD请求转发给ADO.NET数据提供者(ADO.NET
Provider)组件,由其将相关SQL命令直接地发送给数据库。

在实际开发中,大家都使用LINQ to Entities和针对IEnumerable<T>/IQueryable<T>的一组扩展方法完成数据查询工作,几乎不会有人直接使用Entity SQL和 Entity Client。

下图展示了数应用程序运行过程中EF查询的内部处理流程:

可以看到,使用EF的数据查询从发出到真正执行要经过两次“命令树(Command
Tree)转换”,而从数据库中读取的数据,也要经历从
DbDataReader-->EntityDataReader-->IEnmerable<T>的转换。虽然EF采用了缓
存、预编译等手段提升性能,但与ADO.NET相比,由于中间处理环节更多,整个查询处理流程中参与的对象也更多,因此总体性能一般比不上
ADO.NET,并且会占用更多的内存,这也我们是在享用EF带来的方便的同时,所需要付出的代价。

另外,由于所有查询最终还是要转换为SQL命令,因此,有些LINQ to Objects可用的扩展方法,比如Last(),在EF中将不能用,因为EF不知道如何把它们翻译成底层数据库支持的SQL命令。

三、三种开发模式的PK

EF支持三种开发模式:

Code First、Database First和Model First。

到底应该用那一种模式是令人纠结的问题。

方式一:Code First

对于初次接触的人,EF的Code First实在很有点魔幻色彩。下面就让我们来体会一下。

创建两个类:Book(书)和BookReview(书评)。一本书可以有多条书评,因此,它们是一对多的关系:

public class Book

{

public virtual int Id {get;set;}

public virtual string Name { get; set; }

  public virtual List<BookReview> Reviews { get; set; }

}

public class BookReview

{

public int Id{get;set;}

public int BookId { get; set; }

public virtual string Content { get; set; }

public virtual Book AssoicationWithBook { get; set; }

}

好了,现在创建一个派生自DbContext的子类:

public class BookDb : DbContext

{

public DbSet<Book> Books { get; set; }

public DbSet<BookReview> Reviews { get; set; }

}

现在可以在程序中随意写几行代码从数据库中提取数据:

static void Main(string[] args)

{

using (var context = new BookDb())

{

Console.WriteLine("数据库中有{0}本书",context.Books.Count());

}

}

运行一下,如果计算机上安装有SqlExpress,那么或者是在应用程序文件夹,或者是打开SQL Server Management Studio(SSME)查看本机SQLServer,你就会发现,数据库己经创建好,其中的表及表的关联也帮助你完成了:

貌似我什么也没干,一切就OK了,神奇啊!

现在修改Book类,给它添加一个Authors属性,代表书的作者:

public class Book

{

public virtual int Id {get;set;}

public virtual string Name { get; set; }

public virtual string Authors { get; set; }

public virtual List<BookReview> Reviews { get; set; }

}

有了前面良好的第一印象,你一定以为只要再次运行程序,底层数据库就会自动更新,然而,EF会给你当头一棒让你清醒:

很明显,因为你修改了实体类,数据库结构也需要修改,比较郁闷的是,你不能打开创建好的数据库直接修改,而需要使用一个名为“数据库迁移(Database Migration)”的功能,采用两种方式(自动迁移和手动迁移)之一完成。

以自动迁移为例:

首先从从Tools菜单中打开Package Manager Console,然后键入:

enable-migrations –EnableAutomaticMigrations

上述命令会在项目中添加一个Migrations文件夹,其中会有一个Configuration类,为了方便,你需要在其构造函数中添加
“AutomaticMigrationDataLossAllowed = true;”一句,让其自动重建数据库时不理会可能的数据丢失:

internal sealed class Configuration :DbMigrationsConfiguration<EFCodeFirst.BookDb>

{

public Configuration()

{

AutomaticMigrationsEnabled = true;

AutomaticMigrationDataLossAllowed = true;

}

……

}

好了,现在运行update-database命令更新数据库:

再次运行程序,现在将一切OK。

以后每次更改实体类,都必须手动运行update-database命令更新数据库。

手动迁移方式与自动迁移基本一致,不同之处在于它会记录每次更新的情况,从而允许回滚数据库到某个“较老”的版本。

自动方式比较适合于单个人写的应用。而手动方式可以控制数据库结构的更新,比较适合于团队开发。

Code First模式的优点。

从上面的介绍,可以看到Code First有着突出的优点。

(1)是代码清洁,添加自定义逻辑容易。

这是使用Code First最大的好处

特别是在诸如WPF这种可以保持长连接的桌面应用中,可以让实体类实现INotifyProperty接口,将它们放入
ObservableCollection中作为UI界面的绑定数据源,便可以充分利用WPF的数据绑定和EF自动维持实体状态的特点,大幅度地削减代
码。

(2)易于实现继承

Code First在实现继承上非常方便,如果数据实体中有大量的继承的情况,使用Code First很方便,但需要注意的是Code
First在生成数据库表时,默认使用“TPH:Table Per
Hierarchy”方式,把父类子类塞到同一张表中,并在表中添加一个Discriminator字段,表明此记录所属的具体类型。

以下是CodeFirst为拥有继承关系的两个Parent/Child类生成的数据库表,可以看到,Discriminator字段保存了具体的数据类型。

有些朋友问能否把Discriminator字段名给改掉,很遗憾,我没发现可以修改它的方法。

很明显,Code First采用的这种实现策略违反了关系数据库设计范式,对大项目来说,这不易于维护数据的一致性。

实现继承的另外一种方式是TPT(table pertype ),不管子类父类,每个类型一张表。

比如有三个类,Instruct和Student派生自Person,若采用TPT策略,EF将生成三个表,并创建以下的关联:

对于TPH,手写SQL代码很容易,性能高,但对于TPT,EF在生成SQL命令时会产生许多Inner Joint,性能低,另外,对于这种方式存储的数据,手写SQL代码比较麻烦。

Database First和Model First默认情况下都是采用TPH的。

我的建议:除非两实体间确实是IS_A关系,并且在中间层需要使用多态,在“数据存取层(DAL)”尽量少用继承,别自找麻烦

(3)一些开发高手们还为EF提供了一个EntityFramework Power Tools,这一工具增强了Code
First的不少功能,比如它可以从现有数据库直接逆向生成实体类代码,之后就可以修改这些代码,为Code
First方式进行开发省去了不少编码工作。同时,它还能为编写的实体类代码生成只读的数据模型视图,以图形的方式展示出实体类间的关联。

Code First存在的问题

CodeFirst试图“用代码搞掂一切”,其问题在于以下几点:

(1)当Model改变时,往往需要编写代码实现数据库的更改,远不如直接使用数据库所提供的工具修改数据库安全和直观,至少丢失数据的可能性小了很多。

(2)当数据实体间有复杂的关联时,需要使用Fluent API手动编写不少代码定义类之间的关联,这实在麻烦。

(3)对数据库表和关联属性的一些微调(比如改改字段名字,修改字段长度限制等),使用数据库设计工具能轻易实现,但Code First只能通过代码来完成,而且必须使用EF的数据迁移特性,这实在麻烦,整个过程还容易出错。

简而言之,Code First应用的场景是:快速开发,迅速迭代

方式二:Database First

这是EF从1.0开始就支持的特性,其思路是:先设计并建好数据库,然后使用Visual Studio的向导创建EF数据模型并生成实体类代码。

这是最成熟稳定的方式,其设计器相当地完善,基本上能满足实际开发中的各种需求。

我个人认为这是开发正式项目最合适的方式。

当然,DatabaseFirst也有一些问题,主要是需要定制时会有些麻烦。比如:

(1)要想给实体类或生成的DbContext子类添加一些自定义的逻辑,需应用分部类,因为每次更新数据模型,这些代码都会被设计器覆盖并重写。

(2)生成的实体类中不包括任何Data Annotation(所谓“Data
Annotation”就是附在实体类代码上的诸如[Required]之类的东东),因此它需要被转换为另一个类,才能方便地在诸如ASP.NET
MVC之类的项目中使用(比如ASP.NET MVC项目中的视图模型(ViewModel)类往往需要有Data
Annotation,以配合jQuery Validation插件生成网页上的数据验证代码)。

(3)默认情况下实体类与edmx文件放在同一个项目中,想将实体类分离到独立的项目,需要完成一些额外的配置工作(主要是把T4模板文件移到另一个项目,这需要适当地修改T4模板文件中的代码以保证文件路径引用正确)。

方式三:Model First

这种模式是先在可视化设计器中创建实体和它们间的关联,然后设计器生成SQL命令并保存于一个SQL文件中,通过执行这一SQL文件完成数据库的创建和修改工作

我个人感觉:

这种方式最适合于全新开发的项目,从系统分析开始,逐步分析建立和完善领域模型,之后可以立即创建数据库,如果模型有修改,重新生成一个SQL文件,再执行一次即可,非常适合于新项目OOAD阶段的需要。

当进入OOP阶段时,由于数据库己经存在,就可以很方便地转用Database First方式,整个过程流畅自然。

三种模式PK结果:

Code First:对于小的或用于试验的项目,特别是像我经常要讲课的,教学实例使用Code First开发就比较合适,当程序运行时数据库自动生成,比较省事。

DB First:最为成熟,是正规项目的首选方式,因为是由开发者自己(而不是通过一堆“不太可靠”的代码)直接操作数据库,整个过程高度可控,能很好地保证数据安全,贯彻了“数据比代码重要”的理念。

Model First:当开始一个全新的项目,既没有DB,也没有代码时则非常好,是OOAD的好工具,需要时甚至可以直接生成创建各种不同类型数据库(比如MySQL)的SQL代码!

==============================================================

本篇文章介绍了一些EF相关的通用话题,下一篇文章将讨论一下EF实现CRUD的内部原理。

【转】Entity Framework技术导游系列开篇与热身

时间: 2024-11-14 00:18:41

【转】Entity Framework技术导游系列开篇与热身的相关文章

[转]Entity Framework技术导游系列开篇与热身

学习Entity Framework技术期间查阅的优秀文章,出于以后方便查阅的缘故,转载至Blog,可查阅原文:http://blog.csdn.net/bitfan/article/details/12779517 在微软平台写程序有年头了,随着微软数据存取技术的持续演化,我在程序中先后使用过ODBC.DAO.ADO.ADO.NET.LINQ to SQL. Entity Framework这些技术. 近几年来,Entity Framework(后文简称EF)的地位日益上升,成为微软数据存取技

Entity Framework技术导游系列开篇与热身

在微软平台写程序有年头了,随着微软数据存取技术的持续演化,我在程序中先后使用过ODBC.DAO.ADO.ADO.NET.LINQ to SQL. Entity Framework这些技术. 近几年来,Entity Framework(后文简称EF)的地位日益上升,成为微软数据存取技术的主角,也是我个人在开发应用程序时首选的数据存取技术,同时我也在博客园等专业网站上看到业界许多项目也都使用了EF.我放在CSDN下载频道的几讲Entity Framework 5课件(http://download.

Entity Framework技术系列之8:使用Entity Framework技术实现RBAC模型

小分享:我有几张阿里云优惠券,用券购买或者升级阿里云相应产品最多可以优惠五折!领券地址:https://promotion.aliyun.com/ntms/act/ambassador/sharetouser.html?userCode=ohmepe03 前言 RBAC(Role-Based Access Control,基于角色的访问控制),是继DAC(Discretionary Access Control,自主访问控制)和MAC(Mandatory Access Control,强制访问控

Entity Framework技术系列之7:LINQ to Entities

小分享:我有几张阿里云优惠券,用券购买或者升级阿里云相应产品最多可以优惠五折!领券地址:https://promotion.aliyun.com/ntms/act/ambassador/sharetouser.html?userCode=ohmepe03 前言 LINQ(Language Integrated Query,语言集成查询)是一组用于C#和VB.NET语言的扩展,它允许编写C#或者VB.NET代码,以与查询数据库相同的方式操作内存数据.LINQ提Entity Framework技术系

【转】Entity Framework技术系列之7:LINQ to Entities

前言 LINQ(Language Integrated Query,语言集成查询)是一组用于C#和VB.NET语言的扩展,它允许编写C#或者VB.NET代码,以与查询数据库相同的方式操作内存数据. LINQ提Entity Framework技术系列之7:LINQ to Entities供了丰富的类似SQL的查询语法,功能强大且容易上手.下图汇总展示了LINQ技术的官方实现集合: 图1官方LINQ实现汇总图 正 如上图所示,LINQ to Entities 是LINQ技术在实体对象模型中的一种实现

Entity Framework 6 开发系列 目录

2014 年开始接触 Entity Framework 6 也快两年,用它已经沉淀了一个成熟架构,也用来开发了不少大大小小的产品和项目,直到这段时间,才真正有时间来回顾,重新学习它,为让大家更加了解Entity Framework 6,以及想把这两年中,开发过程中碰到的种种问题,跟大家分享,特此想做一个Entity Framework 6 开发系列的计划 第一篇:Entity Framework 简介 第二篇:Entity Framework CodeFirst & Model 映射 第三篇:E

基于.NET的微软ORM框架视频教程(Entity Framework技术)

基于.NET的微软ORM框架视频教程(Entity Framework技术) 第一讲  ORM映射 第二讲 初识EntifyFramework框架 第三讲 LINQ表达式查询 第四讲 LINQ方法查询 第五讲 LINQ TO Entities 第六讲 ObjectQuery查询(上) 第七讲 ObjectQuery查询(下) 第八讲 Entity中的增删改及事务处理 第九讲 Entity中的存储过程使用(完) 源代码及视频

Entity Framework 5.0系列之自动生成Code First代码

在前面的文章中我们提到Entity Framework的“Code First”模式也同样可以基于现有数据库进行开发.今天就让我们一起看一下使用Entity Framework Power Tools如何基于现有数据库生成数据类和数据库上下等. Entity Framework Power Tools 基于现有数据库生成POCO数据类和数据库上下文需要借助Visual Studio一个扩展插件-- Entity Framework Power Tools(一个Code First反向工程工具).

Entity Framework 5.0系列之EF概览

概述 在开发面向数据的软件时我们常常为了解决业务问题实体.关系和逻辑构建模型而费尽心机,ORM的产生为我们提供了一种优雅的解决方案.ADO.NET Entity Framework是.NET开发中一种由ADO.NET驱动的ORM框架,使用Entity Framework开发人员可以不必考虑数据的基础数据表和列,在处理数据时能够以更高的抽象级别进行工作,并能够以相对传统开发编写更少的代码来创建和维护应用程序. 我们知道面向对象的编程与数据存储系统的交换提出了一个难题:类结构通常同关系数据表组织结构