日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

[(转)hystar整理]Entity Framework 教程

發(fā)布時(shí)間:2023/12/9 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 [(转)hystar整理]Entity Framework 教程 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

預(yù)備知識????2

LINQ技術(shù)????2

LINQ技術(shù)的基礎(chǔ) - C#3.0????2

自動(dòng)屬性????2

隱式類型????2

對象初始化器與集合初始化器????3

匿名類????3

擴(kuò)展方法????4

Lambda表達(dá)式????4

.NET中的數(shù)據(jù)訪問????4

DataSet方案????5

改進(jìn)的的DataSet方案????5

手寫代碼通過ADO.NET2.0連接類與數(shù)據(jù)庫交互????5

ORM – LINQ to SQL????6

深入了解Entity Framework????7

Entity Framework的核心 – EDM(Entity Data Model)????7

EDM概述????7

EDM之CSDL????7

EDM之SSDL????11

EDM之MSL????12

EDM中存儲(chǔ)過程的設(shè)計(jì)????15

EDM中ComplexType的設(shè)計(jì)????16

實(shí)體數(shù)據(jù)模型映射方案????17

Entity Framework的原理及使用方式????18

各種使用方式總結(jié)????18

使用技巧及需要注意的問題????21

幾種方法的性能分析及使用選擇????21

其它操作EDM的方式????22

為什么要使用Entity Framework,限制條件及當(dāng)前版本框架的問題????23

EDM中的DML????23

含有Association的EDM的使用????23

?

?

本文檔主要介紹.NET開發(fā)中兩項(xiàng)新技術(shù),.NET平臺(tái)語言中的語言集成查詢技術(shù) - LINQ,與ADO.NET中新增的數(shù)據(jù)訪問層設(shè)計(jì)技術(shù)ADO.NET Entity Framework。ADO.NET的LINQ to Entity部分以LINQ為基礎(chǔ),為了完整性本文檔首先介紹LINQ技術(shù)。

預(yù)備知識

LINQ技術(shù)

LINQ是.NET 3.5中新增的一種技術(shù),這個(gè)技術(shù)擴(kuò)展了.NET平臺(tái)上的編程語言,使其可以更加方便的進(jìn)行數(shù)據(jù)查詢,單純的LINQ技術(shù)主要完成對集合對象(如System.Collection下或System.Collection.Generic命名空間下的對象)的查詢。結(jié)合LINQ Provider可以實(shí)現(xiàn)對XML文件(使用LINQ to XML – 位于System.Xml.Linq命名空間下的類),數(shù)據(jù)庫(可以使用LINQ to SQL或下文要詳細(xì)介紹的LINQ to Entity)等對象的操作。

?

LINQ是一種運(yùn)行時(shí)無關(guān)的技術(shù),其運(yùn)行于CLR2.0之上,微軟對C#3.0與VB9.0的編譯器進(jìn)性擴(kuò)展,從而使其可以將LINQ編寫的程序編譯為可以被CLR2.0的JIT所理解的MSIL。

?

LINQ技術(shù)的基礎(chǔ) - C#3.0

  • 自動(dòng)屬性
  • 隱式類型
  • 對象集合初始化器
  • 匿名類
  • 擴(kuò)展方法
  • Lambda表達(dá)式
  • 自動(dòng)屬性

    這個(gè)概念很簡單,其簡化了我們在.NET的時(shí)候手寫一堆私有成員+屬性的編程方式,我們只需要使用如下方式聲明一個(gè)屬性,編譯器會(huì)自動(dòng)生成所需的成員變量。

    public class Customer

    {

    public int Id { get; set; }

    public string Name { get; set; }

    }

    ????在我使用LINQ完成的項(xiàng)目中,使我了解到自動(dòng)屬性方便的一個(gè)用途如下:

    ????在使用LINQ獲取數(shù)據(jù)的過程中,我們常常需要使用select new語句查詢出一個(gè)對象(往往是IEnumerable類型的)用于數(shù)據(jù)綁定。在一般情況下如果是直接綁定(如直接將查詢結(jié)果賦給一個(gè)Gridview控件的DataSource屬性)我們可以直接select new來返回一個(gè)匿名類的對象。如果我們還需要對這個(gè)集合對象進(jìn)行進(jìn)一步操作,我們將必須使用select new class-name這樣的語言返回一個(gè)類的對象,大部分情況下這個(gè)類只作為實(shí)體的一個(gè)結(jié)構(gòu)而不需要完成一些操作操作,這時(shí)候使用自動(dòng)屬性來完成這個(gè)類將是非常簡潔高效的。

    隱式類型

    這個(gè)名稱可能對你很陌生,但是var這個(gè)關(guān)鍵字應(yīng)該都用過,在C#中使用var聲明一個(gè)對象時(shí),編譯器會(huì)自動(dòng)根據(jù)其賦值語句推斷這個(gè)局部變量的類型。賦值以后,這個(gè)變量的類型也就確定而不可以再進(jìn)行更改。另外var關(guān)鍵字也用于匿名類的聲明。

    ????應(yīng)用場合:var主要用途是表示一個(gè)LINQ查詢的結(jié)果。這個(gè)結(jié)果可能是ObjectQuery<>或IQueryable<>類型的對象,也可能是一個(gè)簡單的實(shí)體類型的對象。這時(shí)使用var聲明這個(gè)對象可以節(jié)省很多代碼書寫上的時(shí)間。

    對象初始化器與集合初始化器

    ????在.NET2.0中構(gòu)造一個(gè)對象的方法一是提供一個(gè)重載的構(gòu)造函數(shù),二是用默認(rèn)的構(gòu)造函數(shù)生成一個(gè)對象,然后對其屬性進(jìn)行賦值。在.NET3.5/C#3.0中我們有一種更好的方式來進(jìn)行對象的初始化。那就是使用對象初始化器。這個(gè)特性也是匿名類的一個(gè)基礎(chǔ),所以放在匿名類之前介紹。

    ????還是那就話,好的代碼強(qiáng)于注釋,下面用幾個(gè)代碼段說明初始化器:

    (代碼出自:李永京的博客 http://lyj.cnblogs.com/)

    基本用法:

    User user = new User { Id = 1, Name = "YJingLee", Age = 22 };

    ?

    嵌套使用:

    User user = new User

    {

    ?? ??Id = 1,

    ?? ??Name = "YJingLee",

    ?? ??Age = 22,

    ?? ??Address = new Address

    ?? ??{

    ?? ???? ??City = "NanJing",

    ?? ???? ??Zip = 21000

    ?? ??}

    };

    ????類似于對象初始化器初始化一個(gè)對象,集合初始化器初始化一個(gè)集合,一句話,有了它你就不用在將元素通過Add逐個(gè)添加了。仍然給出代碼示例:

    基本使用:

    List<int> num = new List<int> { 0, 1, 2, 6, 7, 8, 9 };

    ?

    結(jié)合對象初始化器,我們可以寫出如下簡潔的代碼:

    List<User> user = new List<User>{

    new User{Id=1,Name="YJingLee",Age=22},

    new User{Id=2,Name="XieQing",Age=25},

    };

    應(yīng)用場合:

    ????還是前文提到的select new class-name語法,后面可以直接接一個(gè)初始化器來將查詢結(jié)果返回到這個(gè)對象。

    匿名類

    有了前文初始化器的介紹,匿名類就很簡單了。我們可以使用new { object initializer }或new[]{ object, …}來初始化一個(gè)匿名類或不確定類型的數(shù)組。匿名類的對象需要使用var關(guān)鍵字聲明。示例代碼:

    var p1 = new { Id = 1, Name = "YJingLee", Age = 22 };

    應(yīng)用場合:

    還是同上面的例子提到的當(dāng)直接使用select new { object initializer }這樣的語法就是將一個(gè)LINQ查詢的結(jié)果返回到一個(gè)匿名類中。

    擴(kuò)展方法

    ????擴(kuò)展方法是C#中新增的很重要的特性之一。其對于LINQ的實(shí)現(xiàn)起著關(guān)鍵的作用。在.NET2.0時(shí)代是沒有LINQ的,所以.NET2.0以及之前版本中的集合類在設(shè)計(jì)的時(shí)候沒有預(yù)留用于LINQ的方法。為了在不破壞這個(gè)類現(xiàn)有封裝的前提下又可以為其添加LINQ的支持就需要用到擴(kuò)展方法。

    ????擴(kuò)展方法使用上類似于靜態(tài)方法,但在本質(zhì)上其是實(shí)例方法。這是由于.NET3.5的運(yùn)行環(huán)境仍然為CLR2.0所以語言不可能做很大的變革,這一切都是語法糖。

    下面仍然通過一段代碼來說明擴(kuò)展方法的實(shí)現(xiàn):

    (代碼出自:李永京 http://lyj.cnblogs.com/)

    public static class Extensions

    {

    public static bool IsValidEmailAddress(this string s)

    ????{

    Regex regex = new Regex(@"^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$");

    return regex.IsMatch(s);

    ????}

    }

    如上代碼所示,擴(kuò)展方法為一靜態(tài)方法,聲明于一個(gè)靜態(tài)類,其參數(shù)前加上一個(gè)this關(guān)鍵字,參數(shù)的類型表示這個(gè)擴(kuò)展方法要對這個(gè)類型進(jìn)行擴(kuò)展。如上述代碼表示其要對字符串類型進(jìn)行擴(kuò)展。

    在應(yīng)用上擴(kuò)展方法被作為其擴(kuò)展的類型的靜態(tài)方法來調(diào)用。如下:

    if (email.IsValidEmailAddress())

    {

    ????Response.Write("YJingLee提示:這是一個(gè)正確的郵件地址");

    }

    Lambda表達(dá)式

    Lambda表達(dá)式是對.NET2.0中匿名方法在語法形式上的進(jìn)一步改進(jìn),仍然以代碼說明:

    var inString = list.FindAll(delegate(string s) { return s.Indexof("YJingLee") >= 0; });

    ?

    使用Lambda表達(dá)式代碼將更自然易懂。

    var inString = list.FindAll(s => s.Indexof("YJingLee") >= 0);

    ?

    可以看出,Lambda表達(dá)式格式為:(參數(shù)列表)=>表達(dá)式或語句塊

    另外我對于Lambda表達(dá)式樹的概念還不是很明白,有明白的指點(diǎn)一下。

    ?

    .NET中的數(shù)據(jù)訪問

    這一部分介紹.NET中不同的數(shù)據(jù)訪問層的使用方式,由此得出Entity Framework在一個(gè).NET系統(tǒng)中的應(yīng)用及其在原有設(shè)計(jì)基礎(chǔ)上的改變。從大的方面來看數(shù)據(jù)訪問的設(shè)計(jì)方案基本有如下幾類:

    • DataSet
    • 手寫代碼通過ADO.NET2.0連接類與數(shù)據(jù)庫交互
    • ORM組件

    DataSet方案

    最基本的Dataset數(shù)據(jù)訪問的實(shí)現(xiàn)使用下圖表示:

    圖1

    如圖所示,DataSet與數(shù)據(jù)源之間通過DataAdapter連接,邏輯中直接訪問DataSet獲取數(shù)據(jù),或是通過ADO.NET2.0的非連接類,或者通過強(qiáng)類型DataSet以一種類型安全的方式訪問數(shù)據(jù)。

    ????缺點(diǎn)邏輯代碼與數(shù)據(jù)訪問代碼耦合高。

    改進(jìn)的的DataSet方案

    圖2

    這種設(shè)計(jì)方式將業(yè)務(wù)所需的實(shí)體抽象出來,并把對DataSet的操作封裝在其中,這樣一定程序上解除業(yè)務(wù)邏輯與數(shù)據(jù)訪問間的耦合。

    手寫代碼通過ADO.NET2.0連接類與數(shù)據(jù)庫交互

    這種方式是我使用的最多的一種方式,其可以提供最大的控制能力,且效率最高,唯一的不足是當(dāng)業(yè)務(wù)變化時(shí)修改數(shù)據(jù)訪問代碼的工作量比較大,通過代碼生成器也能一定程度上解決這個(gè)問題

    ?

    ORM – LINQ to SQL

    在.NET平臺(tái)下ORM的解決方案有不少,本文只討論兩個(gè)微軟官方的解決方案。先是LINQ to SQL技術(shù)。LINQ to SQL是一個(gè)將不再更新的技術(shù)。其有很多不足之處,如,不能靈活的定義對象模型與數(shù)據(jù)表之間的映射、無法擴(kuò)展提供程序只能支持SQL Server等。

    這樣數(shù)據(jù)訪問層的設(shè)計(jì)如下所示:

    圖3

    ?

    ORM – ADO.NET Entity Framework

    作為下一代數(shù)據(jù)訪問的技術(shù)領(lǐng)導(dǎo)者。Entity Framework的設(shè)計(jì)很多地方都保留了高擴(kuò)展性。其最重要的一個(gè)改進(jìn)在于其映射定義的靈活性。先來看下圖:

    圖4

    由圖可以看出,使用Entity Framework可以充分的定義與數(shù)據(jù)庫表映射的實(shí)體,并將這個(gè)實(shí)體直接用于業(yè)務(wù)邏輯層或作為服務(wù)的數(shù)據(jù)契約。實(shí)體設(shè)計(jì)較其他技術(shù)的優(yōu)勢體現(xiàn)在以下幾方面:

    • 創(chuàng)建ComplexType(CSDL部分有討論)
    • EntitySet的繼承

    使用Entity Framework后,可以將實(shí)體類的設(shè)計(jì)工作完全放在EDM的設(shè)計(jì)過程中,而不再需要手工寫一些大同小異的代碼,并且對這個(gè)實(shí)體模型(包含于EDM中)可以在運(yùn)行時(shí)修改并生效。另外,開發(fā)人員與數(shù)據(jù)庫直接打交道的次數(shù)將大大減少,大部分時(shí)間開發(fā)人員只需操作實(shí)體模型,框架會(huì)自動(dòng)完成對數(shù)據(jù)庫的操作。下文將詳細(xì)討論上圖所示的EDM。

    深入了解Entity Framework

    Entity Framework的核心 – EDM(Entity Data Model)

    EDM概述

    實(shí)體數(shù)據(jù)模型,簡稱EDM,由三個(gè)概念組成。概念模型由概念架構(gòu)定義語言文件 (.csdl)來定義,映射由映射規(guī)范語言文件 (.msl),存儲(chǔ)模型(又稱邏輯模型)由存儲(chǔ)架構(gòu)定義語言文件 (.ssdl)來定義。這三者合在一起就是EDM模式。EDM模式在項(xiàng)目中的表現(xiàn)形式就是擴(kuò)展名為.edmx的文件。這個(gè)包含EDM的文件可以使用Visual Studio中的EDM設(shè)計(jì)器來設(shè)計(jì)。由于這個(gè)文件本質(zhì)是一個(gè)xml文件,可以手工編輯此文件來自定義CSDL、MSL與SSDL這三部分。下面詳細(xì)分析一下這個(gè)xml文件及三個(gè)其重要組成部分:

    這個(gè)文件展示了示例項(xiàng)目完整的EDM文件的XML形式:

    文件

    這個(gè)設(shè)計(jì)器生成的文件的注釋可以使你很清楚的明白這個(gè)EDM文件的組成。一點(diǎn)點(diǎn)分析一下,第一行表明這是一個(gè)xml文件。

    <?xml version="1.0" encoding="utf-8"?>

    以下這一行是EDM的根節(jié)點(diǎn),定義了一個(gè)表明版本的屬性及這個(gè)EDM使用的命名空間:

    <edmx:Edmx Version="1.0" xmlns:edmx="http://schemas.microsoft.com/ado/2007/06/edmx">

    接下來由注釋可以看到EDM被分為兩部分,第一部分是EDM的核心,第二部分用于實(shí)體設(shè)計(jì)器,這一部分不用研究。

    第一部分中節(jié)點(diǎn)<edmx:Runtime>下定義了以下三部分:

    EDM之CSDL

    ????CSDL定義了EDM或者說是整個(gè)程序的靈魂部分 – 概念模型。當(dāng)前流行的軟件設(shè)計(jì)方法通常都是由設(shè)計(jì)其概念模型起步。說概念模型可能比較抽象一個(gè)更容易接受的名字就是實(shí)體類。實(shí)體類是面向?qū)ο笤O(shè)計(jì)中一個(gè)最根本的組成部分,其體現(xiàn)了現(xiàn)實(shí)世界中對象作為一種計(jì)算中可以表示的對象設(shè)計(jì)方法。而EDM的CSDL就是要達(dá)到這樣一個(gè)目的。這個(gè)在下文介紹Entity Framework優(yōu)點(diǎn)時(shí)另有說明。

    ????這個(gè)文件完全以程序語言的角度來定義模型的概念。即其中定義的實(shí)體、主鍵、屬性、關(guān)聯(lián)等都是對應(yīng)于.NET Framework中的類型。下面xml element來自作業(yè)提交系統(tǒng)(有刪節(jié)):

    <!-- CSDL content -->

    <edmx:ConceptualModels>

    <Schema Namespace="ASSModel" Alias="Self" xmlns="http://schemas.microsoft.com/ado/2006/04/edm">

    <EntityContainer Name="ASSEntities">

    <FunctionImport Name="GETHOUSEWORKDONE" EntitySet="UpAssignments" ReturnType="Collection(Self.UpAssignments)">

    <Parameter Name="StuID" Type="Int32" Mode="In" />

    <Parameter Name="ClassID" Type="Int32" Mode="In" />

    <Parameter Name="Semester" Type="String" Mode="In" />

    </FunctionImport>

    <!-- 以上刪節(jié) – 5個(gè)存儲(chǔ)過程 -->

    ?

    <EntitySet Name="Assignments" EntityType="ASSModel.Assignments" />

    <EntitySet Name="Classes" EntityType="ASSModel.Classes" />

    <EntitySet Name="Courses" EntityType="ASSModel.Courses" />

    <EntitySet Name="SetCourses" EntityType="ASSModel.SetCourses" />

    <EntitySet Name="Students" EntityType="ASSModel.Students" />

    <EntitySet Name="Teachers" EntityType="ASSModel.Teachers" />

    <EntitySet Name="UpAssignments" EntityType="ASSModel.UpAssignments" />

    ?

    <AssociationSet Name="FK_SetCourses_Classes" Association="ASSModel.FK_SetCourses_Classes">

    <End Role="Classes" EntitySet="Classes" />

    <End Role="SetCourses" EntitySet="SetCourses" />

    </AssociationSet>

    <!-- 以上刪節(jié) – 6個(gè)關(guān)系集 -->

    ?

    </EntityContainer>

    ?

    <!-- 以下保留一個(gè)EntityType作為示例 -->

    <EntityType Name="Students">

    <Key>

    <PropertyRef Name="StuID" />

    </Key>

    <Property Name="StuID" Type="Int32" Nullable="false" />

    <Property Name="StuName" Type="String" Nullable="false" MaxLength="10" Unicode="true" FixedLength="true" />

    <Property Name="Pswd" Type="String" Nullable="false" MaxLength="50" Unicode="false" FixedLength="true" />

    <NavigationProperty Name="Classes" Relationship="ASSModel.FK_Students_Classes" FromRole="Students" ToRole="Classes" />

    <NavigationProperty Name="UpAssignments" Relationship="ASSModel.FK_UpAssignments_Students" FromRole="Students" ToRole="UpAssignments" />

    </EntityType>

    ?

    <!-- 僅保留與上文AssociationSet對應(yīng)的Association -->

    <Association Name="FK_SetCourses_Classes">

    <End Role="Classes" Type="ASSModel.Classes" Multiplicity="1" />

    <End Role="SetCourses" Type="ASSModel.SetCourses" Multiplicity="*" />

    </Association>

    </Schema>

    </edmx:ConceptualModels>

    這部分XML文檔,Schema是CSDL的根元素,其中定義的Namespace是用于ObjectContext與EntityClass的命名空間,Alias-別名為此命名空間Namespace指定一個(gè)易記的名稱,在定義Alias之后,在此Schema內(nèi)的Element均可以該Alias作為Namespace的別名。Alias的使用可以參考如下xml element:

    <FunctionImport Name="GETHOUSEWORKDONE" EntitySet="UpAssignments" ReturnType="Collection(Self.UpAssignments)">

    在這個(gè)根元素的內(nèi)部的文檔結(jié)構(gòu)第一部分 – 實(shí)體容器大致如下:

    <EntityContainer />

    <FunctionImport />

    <EntitySet />

    <AssociationSet />

    </EntityContainer>

    下面的表格說明了這些節(jié)點(diǎn)及其屬性的作用

    EntityContainer

    ?

    Name

    EntityContainer的名稱,其將作為產(chǎn)生的ObjectContext類的名稱

    ?

    EntitySet

    ?

    Name

    ObjectContext內(nèi)與此Entity類型對應(yīng)的屬性名

    EntityType

    ObjectContext內(nèi)與此Entity類型對應(yīng)的屬性的類型

    AssociationSet

    ?
    ?

    End

    有兩個(gè)End子節(jié)點(diǎn),分別描述建立此關(guān)系的兩個(gè)EntitySet

    ?

    Role

    對應(yīng)到Association中End節(jié)的Role屬性,起到將AssociationSet與Association相關(guān)連的作用。

    ?

    FunctionImport

    詳見存儲(chǔ)過程設(shè)計(jì)部分

    可以看出,Entity與Assciation都被分開定義與兩個(gè)部分,這樣設(shè)計(jì)是出于當(dāng)有多個(gè)EntityContainer時(shí),其中的EntitySet或AssociationSet可以共享Entity或Association的定義。

    ????接下來看一下CSDL中最后一部分,Entity與Association的定義。

    首先是Entity:

    <EntityType Name="Students">

    <Key>

    <PropertyRef Name="StuID" />

    </Key>

    <Property Name="StuID" Type="Int32" Nullable="false" />

    <Property Name="StuName" Type="String" Nullable="false" MaxLength="10" Unicode="true" FixedLength="true" />

    <Property Name="Pswd" Type="String" Nullable="false" MaxLength="50" Unicode="false" FixedLength="true" />

    <NavigationProperty Name="Classes" Relationship="ASSModel.FK_Students_Classes" FromRole="Students" ToRole="Classes" />

    <NavigationProperty Name="UpAssignments" Relationship="ASSModel.FK_UpAssignments_Students" FromRole="Students" ToRole="UpAssignments" />

    </EntityType>

    下表說明了其屬性及其子節(jié)點(diǎn)與子節(jié)點(diǎn)的屬性的含義:

    ?

    ?

    ?

    ?

    ?

    ?

    ?

    ?

    ?

    ?

    EntityType

    ?

    Name

    Entity Class的名稱

    Abstract

    是否為抽象類

    BaseType

    父類

    ?

    Key

    主鍵

    ?

    Property

    主鍵之屬性

    Name

    屬性名

    Property

    屬性

    Name

    屬性名

    Type

    屬性類型

    Nullable

    是否允許null

    MaxLength

    屬性最大長度

    FixLength

    是否固定長度

    NavigationProperty

    關(guān)系屬性

    Name

    屬性名

    Relationship

    對應(yīng)的Association

    FromRole、ToRole

    區(qū)別關(guān)系兩方的父與子

    ?

    最后Association節(jié),這是真正定義關(guān)系的地方。首先看示例:

    <!-- 僅保留與上文AssociationSet對應(yīng)的Association -->

    <Association Name="FK_SetCourses_Classes">

    <End Role="Classes" Type="ASSModel.Classes" Multiplicity="1" />

    <End Role="SetCourses" Type="ASSModel.SetCourses" Multiplicity="*" />

    </Association>

    這一節(jié)符合以下結(jié)構(gòu):

    <Association>

    <End />

    <ReferentialConstraint>

    <Principal>

    <PropertyRef />

    </Principal>

    <Dependent>

    <PropertyRef />

    </Dependent>

    </ReferentialConstraint>

    </Association>

    屬性及其子元素屬性的說明:

    ?

    ?

    Association

    ?

    Name

    Association的名稱

    ?

    End

    類似于AssociationSet,Association也有兩個(gè)End節(jié)點(diǎn)。

    Name

    End名稱

    Type

    EntityType的名稱

    Role

    此End的Role,與AssociationSet的End的Role屬性相聯(lián)系

    Multiplicity

    關(guān)聯(lián)多重性,值為0、1或*

    ReferentialConstraint

    外鍵條件限制

    ?

    Principal

    主要條件

    Role

    對應(yīng)于End中的Role

    ?

    PropertyRef

    外鍵屬性

    Name

    屬性名稱

    Dependent

    依存條件

    Role

    對應(yīng)于End中的Role

    ?

    PropertyRef

    外鍵屬性

    Name

    屬性名

    ?

    另外上面示例未涉及的概念,如下:

    視圖

    ????在EDM設(shè)計(jì)器中添加視圖基本與添加實(shí)體表一致,所生成的xml自行對照。某些環(huán)境下可能無法添加視圖,原因未知,另外對于沒有主鍵的表目前版本EntityFramework支持不好,在設(shè)計(jì)器中無法添加,及時(shí)通過手工編輯xml的方式強(qiáng)行添加,在使用過程中也會(huì)出現(xiàn)問題。

    ComplexType(復(fù)雜類型)

    按MSDN中的例子,先描述如下場景。在一個(gè)銷售系統(tǒng)中我們需要在一個(gè)訂單中包含一個(gè)描述客戶地址的實(shí)體,而這個(gè)實(shí)體又能良好的與存儲(chǔ)模型映射起來,由于數(shù)據(jù)庫不支持地址這種類型,所以我們可以將地址的每個(gè)字段與數(shù)據(jù)庫相映射。且在概念模型中,及在C#代碼可以控制的范圍內(nèi),地址仍然作為一個(gè)獨(dú)立的類型存在。由于EDM設(shè)計(jì)器不支持以可視化方式創(chuàng)建Complex Type,我們需要手動(dòng)編輯CSDL與MSL來完成復(fù)雜類型的創(chuàng)建與映射。這部分示例將在介紹MSL后給出。

    ?

    EDM之SSDL

    這個(gè)文件中描述了表、列、關(guān)系、主鍵及索引等數(shù)據(jù)庫中存在的概念。

    <!-- SSDL content -->

    <edmx:StorageModels>

    <Schema Namespace="ASSModel.Store" Alias="Self" Provider="System.Data.SqlClient" ProviderManifestToken="2008" xmlns:store="http://schemas.microsoft.com/ado/2007/12/edm/EntityStoreSchemaGenerator" xmlns="http://schemas.microsoft.com/ado/2006/04/edm/ssdl">

    <EntityContainer Name="ASSModelStoreContainer">

    <EntitySet Name="Assignments" EntityType="ASSModel.Store.Assignments" store:Type="Tables" Schema="dbo" />

    <!-- 省略7個(gè)EntitySet的定義 -->

    </EntityContainer>

    ?

    <!-- 以下省略7個(gè)EntityType的定義 -->

    <EntityType Name="Assignments">

    <Key>

    <PropertyRef Name="AssID" />

    </Key>

    <Property Name="AssID" Type="int" Nullable="false" StoreGeneratedPattern="Identity" />

    <Property Name="AssName" Type="nchar" Nullable="false" MaxLength="20" />

    <Property Name="AssDes" Type="nvarchar" MaxLength="500" />

    <Property Name="SCID" Type="int" Nullable="false" />

    <Property Name="Deadline" Type="datetime" Nullable="false" />

    <Property Name="QuesFileName" Type="nvarchar" MaxLength="500" />

    <Property Name="QuesFileUrl" Type="nvarchar" Nullable="false" MaxLength="500" />

    </EntityType>

    ?

    <!-- 保留與CSDL中對應(yīng)的Function -->

    <Function Name="GETHOUSEWORKDONE" Aggregate="false" BuiltIn="false" NiladicFunction="false" IsComposable="false" ParameterTypeSemantics="AllowImplicitConversion" Schema="dbo">

    <Parameter Name="StuID" Type="int" Mode="In" />

    <Parameter Name="ClassID" Type="int" Mode="In" />

    <Parameter Name="Semester" Type="varchar" Mode="In" />

    </Function>

    ?

    </Schema>

    </edmx:StorageModels>

    看文檔的結(jié)構(gòu),SSDL與CSDL很詳細(xì),只是其中EntityType等使用數(shù)據(jù)庫的概念的描述。

    這其中有一個(gè)需要稍微介紹節(jié)點(diǎn),DefiningQuery,首先看一下其出現(xiàn)的位置:

    EntityContainer

    ?
    ?

    EntitySet

    ?
    ?

    DefiningQuery

    通過查詢定義一個(gè)SSDL的EntitySet

    ?

    特定于存儲(chǔ)的查詢語句

    DefiningQuery定義通過實(shí)體數(shù)據(jù)模型 (EDM) 內(nèi)的客戶端投影映射到數(shù)據(jù)存儲(chǔ)視圖的查詢。此類映射是只讀的。也就是說如果想要更新此類EntitySet,需要使用下文介紹存儲(chǔ)過程時(shí)提到的定義更新實(shí)體的存儲(chǔ)過程的方法,使用定義的存儲(chǔ)過程來更新這樣的EntitySet。當(dāng)在實(shí)體類設(shè)計(jì)器中導(dǎo)入無主鍵的表時(shí),會(huì)自動(dòng)生成此類使用DefiningQuery定義的EntitySet,要式樣Entity Framework提供的自動(dòng)更新服務(wù)而不定義存儲(chǔ)過程,需要給數(shù)據(jù)表添加一個(gè)適當(dāng)?shù)闹麈I,刪除DefiningQuery節(jié)點(diǎn)并更新數(shù)據(jù)模型。

    EDM之MSL

    這個(gè)文件即上面所述的CSDL與SSDL的對應(yīng),主要包括CSDL中屬性與SSDL中列的對應(yīng)。

    <!-- C-S mapping content -->

    <edmx:Mappings>

    <Mapping Space="C-S" xmlns="urn:schemas-microsoft-com:windows:storage:mapping:CS">

    <EntityContainerMapping StorageEntityContainer="ASSModelStoreContainer" CdmEntityContainer="ASSEntities">

    <EntitySetMapping Name="Assignments">

    <EntityTypeMapping TypeName="IsTypeOf(ASSModel.Assignments)">

    <MappingFragment StoreEntitySet="Assignments">

    <ScalarProperty Name="QuesFileName" ColumnName="QuesFileName" />

    <ScalarProperty Name="AssDes" ColumnName="AssDes" />

    <ScalarProperty Name="AssID" ColumnName="AssID" />

    <ScalarProperty Name="AssName" ColumnName="AssName" />

    <ScalarProperty Name="Deadline" ColumnName="Deadline" />

    <ScalarProperty Name="QuesFileUrl" ColumnName="QuesFileUrl" />

    </MappingFragment>

    </EntityTypeMapping>

    </EntitySetMapping>

    <!-- 省略EntitySetMapping若干 -->

    ?

    <!-- 保留對應(yīng)于CSDLSSDLFunctionImportMapping -->

    <FunctionImportMapping FunctionImportName="GETHOUSEWORKDONE" FunctionName="ASSModel.Store.GETHOUSEWORKDONE" />

    ?

    <AssociationSetMapping Name="FK_UpAssignments_Assignments" TypeName="ASSModel.FK_UpAssignments_Assignments" StoreEntitySet="UpAssignments">

    <EndProperty Name="Assignments">

    <ScalarProperty Name="AssID" ColumnName="AssID" />

    </EndProperty>

    <EndProperty Name="UpAssignments">

    <ScalarProperty Name="UpAssID" ColumnName="UpAssID" />

    </EndProperty>

    </AssociationSetMapping>

    <!-- 省略AssociationSetMapping若干 -->

    ?

    </EntityContainerMapping>

    </Mapping>

    </edmx:Mappings>

    ????如上代碼所示,MSL的根節(jié)點(diǎn)為Mapping,其中可以包含多個(gè)EntityContainerMapping(上例只有一個(gè)),每一個(gè)EntityContainerMapping對應(yīng)著兩個(gè)分別來自CSDL與SSDL的EntityContainer。這個(gè)EntityContainerMapping就是描述這兩個(gè)EntityContainer間的對應(yīng)。下面再給出一段代碼展示EntityContainerMapping的基本格式。

    <EntityContainerMapping StorageEntityContainer="" CdmEntityContainer="">

    <EntitySetMapping>

    <EntityTypeMapping>

    <MappingFragment>

    <ScalarProperty />

    </MappingFragment>

    <ModificationFunctionMapping>

    <InsertFunction />

    <DeleteFunction />

    <UpdateFunction />

    </ ModificationFunctionMapping>

    </EntityTypeMapping>

    </EntitySetMapping>

    ?

    <AssociationSetMapping>

    <EndProperty>

    <ScalarProperty />

    </EndProperty>

    </AssociationSetMapping>

    ?

    <FunctionImportMapping />

    </EntityContainerMapping>

    同上文,下面列出這些節(jié)點(diǎn)的屬性

    EntityContainerMapping

    ?

    StorageEntityContainer

    SSDL中的EntityContainer名稱

    CdmEntityContainer

    CSDL中的EntityContainer名稱

    ?

    EntitySetMapping

    EntityContainer中每個(gè)EntitySet的對應(yīng)

    Name

    EntitySetMapping的名稱

    ?

    EntityTypeMapping

    描述CSDL中EntityType與SSDL中EntityType的對應(yīng)

    Name

    EntityTypeMapping的名稱

    TypeName

    對應(yīng)CSDL內(nèi)Entity的名稱 – 格式:IsTypeOf(<名稱>)

    注:這個(gè)類及其子類將共享此EntityTypeMapping

    ?

    MappingFragment

    描述屬性及字段間的對應(yīng)

    StoreEntitySet

    SSDL中的EntitySet名稱

    (由于CSDL中一個(gè)EntitySet可以對應(yīng)多個(gè)SSDL中的EntitySet)

    ?

    ScalarProperty

    屬性與字段對應(yīng)

    Name

    CSDL中的屬性名

    ColumnName

    SSDL中的字段名稱

    ?

    Condition

    詳見說明2

    ColumnName

    列名

    Value

    ModificationFunctionMapping

    CUD對應(yīng)的存儲(chǔ)過程

    ?

    InsertFunction/ UpdateFunction / DeleteFunction

    FunctionName

    ?

    QueryView

    ?
    ?

    Entity SQL

    AssociationSetMapping

    描述CSDL中的AssociationSet與SSDL中的EntitySet的對應(yīng)關(guān)系

    Name

    AssociationSetMapping的名稱

    StoreEntitySet

    SSDL中EntitySet的名稱

    TypeName

    CSDL中AssociationSet的名稱

    ?

    EndProperty

    一個(gè)AssociationSetMapping中有兩個(gè)EndProperty

    分別對應(yīng)CSDL中兩個(gè)End Role

    Name

    EndProperty的名稱

    ?

    ScalarProperty

    關(guān)系屬性對應(yīng)

    Name

    CSDL中的屬性名

    ColumnName

    SSDL中的字段名稱

    ModificationFunctionMapping

    C/D對應(yīng)的存儲(chǔ)過程

    ?

    InsertFunction/ DeleteFunction

    FunctionName

    ?

    QueryView

    ?
    ?

    EntitySQL

    FunctionImportMapping

    用于描述CSDL與SSDL間函數(shù)及函數(shù)參數(shù)的對應(yīng)(詳見下文存儲(chǔ)過程部分)

    ?

    說明1:以上表中很重要的一個(gè)屬性是MappingFragment中的StoreEntitySet屬性,就像這個(gè)屬性的說明中所說,其描述了CSDL的Entity對應(yīng)到的SSDL的Entity的名稱。這是實(shí)現(xiàn)下文EDM映射方案中第二條將一個(gè)概念模型的實(shí)體映射到多個(gè)存儲(chǔ)模型的實(shí)體的關(guān)鍵設(shè)置。

    說明2:Contain這個(gè)元素及其屬性的作用是,當(dāng)多個(gè)概念模型實(shí)體映射到一個(gè)存儲(chǔ)模型實(shí)體時(shí),該元素的屬性決定了在什么情況下一個(gè)概念模型實(shí)體映射到指定的存儲(chǔ)模型實(shí)體。

    說明3:QueryView 元素定義概念模型中的實(shí)體與存儲(chǔ)模型中的實(shí)體之間的只讀映射。使用根據(jù)存儲(chǔ)模型計(jì)算的 Entity SQL 查詢定義此查詢視圖映射,并以概念模型中的實(shí)體表達(dá)結(jié)果集。同DefiningQuery定義的查詢。此映射也是只讀的。就是說如果想要更新此類EntitySet,也需要使用下文介紹存儲(chǔ)過程時(shí)提到的定義更新實(shí)體的存儲(chǔ)過程的方法,使用定義的存儲(chǔ)過程來更新這樣的EntitySet。當(dāng)多對多關(guān)聯(lián)在存儲(chǔ)模型中所映射到的實(shí)體表示關(guān)系架構(gòu)中的鏈接表時(shí),必須為此鏈接表在AssociationSetMapping 元素中定義一個(gè)QueryView元素。定義查詢視圖時(shí),不能在 AssociactionSetMapping 元素上指定 StorageSetName 屬性。定義查詢視圖時(shí),AssociationSetMapping 元素不能同時(shí)包含 EndProperty 映射。

    EDM中存儲(chǔ)過程的設(shè)計(jì)

    目前版本(VS2008SP1)的實(shí)體設(shè)計(jì)器對存儲(chǔ)過程支持不完善,只能手工編輯這三個(gè)文件中的存儲(chǔ)過程部分,包括:

  • CSDL中的FunctionImport元素,其屬性及說明如下所示:

    FunctionImport

    ?

    Name

    (在程序中調(diào)用的)函數(shù)的名稱

    EntitySet

    當(dāng)函數(shù)返回實(shí)體對象時(shí),需使用此屬性指定對應(yīng)的EntitySet

    ReturnType

    函數(shù)返回值的類型

    ?

    Parameter

    以下用于參數(shù)子節(jié)點(diǎn)中的屬性定義

    Name

    參數(shù)的名稱

    Type

    參數(shù)的類型

    Mode

    參數(shù)的傳遞方式(In, Out或InOut)

    MaxLength

    參數(shù)值最大長度

    Precision

    參數(shù)值的精確度,用于數(shù)字類型

    Scale

    浮點(diǎn)數(shù)小數(shù)位

  • SSDL中的Function節(jié)

    Function

    ?

    Name

    存儲(chǔ)過程名稱

    Aggregate

    是否為聚合函數(shù)(存儲(chǔ)過程)

    BuiltIn

    是否為內(nèi)建存儲(chǔ)過程

    NiladicFunction

    是否為無參數(shù)存儲(chǔ)過程

    IsComposable

    True為自定義函數(shù),False為存儲(chǔ)過程

    ParameterTypeSemantics

    參數(shù)類型轉(zhuǎn)換方式

    ReturnType

    存儲(chǔ)過程返回類型

  • MSL中的FunctionImportMapping節(jié)

    FunctionImportMapping

    ?

    FunctionImportName

    CSDL中FunctionImport的名稱

    FunctionName

    SSDL中Function Element的名稱

    這面總結(jié)的是用于返回實(shí)體對象的查詢(存儲(chǔ)過程)。

  • 下面分別描述一下有關(guān)修改操作的存儲(chǔ)過程的使用:

  • 使用插入、更新或刪除實(shí)體數(shù)據(jù)的存儲(chǔ)過程,需要修改如下兩個(gè)文件:
    SSDL,對其的修改要求與上文表中列出的一致:

    MSL,需要對一下節(jié)點(diǎn)進(jìn)行定義:

  • EntityContainerMapping

    ?
    ?

    EntitySetMapping

    EntityContainer中每個(gè)EntitySet的對應(yīng)

    ?

    EntityTypeMapping

    描述CSDL中EntityType與SSDL中EntityType的對應(yīng)

    ?

    ModificationFunctionMapping

    CUD對應(yīng)的存儲(chǔ)過程

    ?

    InsertFunction/ UpdateFunction / DeleteFunction

    FunctionName

    ?

    ?

  • 使用創(chuàng)建或刪除在數(shù)據(jù)源中使用鏈接表實(shí)現(xiàn)的實(shí)體類型之間的多對多關(guān)系的存儲(chǔ)過程需要修改如下兩個(gè)文件:
    SSDL,對其的修改要求與上文表中列出的一致:

    MSL,需要對一下節(jié)點(diǎn)進(jìn)行定義:

  • EntityContainerMapping

    ?
    ?

    AssociationSetMapping

    描述CSDL中的AssociationSet與SSDL中的EntitySet的對應(yīng)關(guān)系

    ?

    ModificationFunctionMapping

    C/D對應(yīng)的存儲(chǔ)過程

    ?

    InsertFunction/ DeleteFunction

    FunctionName

    ?

    ?

    EDM中ComplexType的設(shè)計(jì)

    再談Complex Type,上文大致介紹了復(fù)雜類型的概念及作用,現(xiàn)在開始看一下具體怎樣實(shí)現(xiàn)。前文已經(jīng)提到實(shí)現(xiàn)復(fù)雜類型關(guān)鍵是在CSDL與MSL,而與SSDL無關(guān)。

    ????首先應(yīng)該在CSDL中怎加這樣一節(jié),此節(jié)與<EntityType></EntityType>節(jié)同級,其結(jié)構(gòu)如下:

    <ComplexType>

    <Property />

    </ComplexType>

    節(jié)點(diǎn)及其屬性含義如下:

    ComplexType

    復(fù)雜類型

    Name

    復(fù)雜類型的名稱

    ?

    Property

    屬性

    Name

    屬性名

    Type

    屬性類型

    Nullable

    是否允許null

    MaxLength

    屬性最大長度

    FixLength

    是否固定長度

    ????然后在MSL中<MappingFragment>下與<ScalarProperty />同級的位置添加如下節(jié):

    <ComplexProperty>

    <ScalarProperty />

    </ComplexProperty>

    具體的節(jié)及其屬性含義如下:

    ComplexProperty

    復(fù)雜類型屬性

    Name

    復(fù)雜類型屬性名稱

    TypeName

    CSDL中定義的ComplexType的名稱。格式"CSDN_Namespace.ComplexTypeName"

    ?

    ScalarProperty

    關(guān)系屬性對應(yīng)

    Name

    CSDL中的屬性名

    ColumnName

    SSDL中的字段名稱

    ?

    實(shí)體數(shù)據(jù)模型映射方案

    實(shí)體框架支持各種方式用于在實(shí)體數(shù)據(jù)模型 (EDM) 中將概念模型映射到關(guān)系數(shù)據(jù)。有關(guān)更多信息,請參見 實(shí)體框架中的數(shù)據(jù)建模。

    實(shí)體框架當(dāng)前支持以下實(shí)體數(shù)據(jù)模型 (EDM) 映射方案。

    編號

    映射方案

    說明

    1

    簡單映射

    在此映射方案中,概念模型中的每個(gè)實(shí)體都映射到存儲(chǔ)模型中的單個(gè)表。這是實(shí)體數(shù)據(jù)模型工具所生成的默認(rèn)映射。

    2

    實(shí)體拆分

    在此映射方案中,概念模型中單個(gè)實(shí)體的屬性映射到兩個(gè)或更多基礎(chǔ)表中的列。在此方案中,表必須共享公共主鍵。

    其設(shè)計(jì)方式見EDM之MSL部分說明1。

    3

    存儲(chǔ)模型中的水平分區(qū)

    在此映射方案中,概念模型中的單個(gè)實(shí)體類型映射到具有相同架構(gòu)的兩個(gè)或更多表。實(shí)體基于概念模型中定義的條件映射到表中。

    使用場合:使一個(gè)概念模型的實(shí)體映射到不同數(shù)據(jù)源的存儲(chǔ)模型的實(shí)體。

    另見:EDM之MSL部分說明2。

    4

    概念模型中的水平分區(qū)

    在此映射方案中,概念模型中具有相同屬性的多個(gè)實(shí)體類型映射到同一個(gè)表。條件子句用于指定表中的數(shù)據(jù)分別屬于哪個(gè)實(shí)體類型。此映射類似于類型5。

    這種方式也用到MSL中的Conditon來決定映射關(guān)系,見EDM之MSL部分說明2。

    5

    每個(gè)層次結(jié)構(gòu)一個(gè)表繼承

    在此映射方案中,繼承層次結(jié)構(gòu)中的所有類型都映射到同一個(gè)表。條件子句用于定義實(shí)體類型。

    見EDM之MSL部分說明2。

    6

    每種類型一個(gè)表繼承

    在此映射方案中,所有類型都分別映射到各自的表。僅屬于某個(gè)基類型或派生類型的屬性存儲(chǔ)在映射到該類型的一個(gè)表中。

    7

    每種具體類型一個(gè)表繼承

    在此映射方案中,每個(gè)非抽象類型分別映射到不同的表。所有這些表所包含的列必須映射到派生類型的所有屬性(包括從基類型繼承的屬性)。

    8

    每種類型多個(gè)實(shí)體集

    在此映射方案中,單個(gè)實(shí)體類型在概念模型中以兩個(gè)或更多獨(dú)立的實(shí)體集進(jìn)行表示。每個(gè)實(shí)體集分別映射到存儲(chǔ)模型中的一個(gè)單獨(dú)的表。

    其設(shè)計(jì)方式見EDM之MSL部分說明1。

    9

    復(fù)雜類型

    復(fù)雜類型是沒有鍵屬性的實(shí)體類型的非標(biāo)量屬性。復(fù)雜類型可以包含其他嵌套的復(fù)雜類型。復(fù)雜類型映射到存儲(chǔ)模型中的表。

    復(fù)雜類型在上文有單獨(dú)介紹

    10

    函數(shù)導(dǎo)入映射

    在此方案中,存儲(chǔ)模型中的存儲(chǔ)過程映射到概念模型中的 FunctionImport 元素。執(zhí)行此函數(shù)可使用映射的存儲(chǔ)過程返回實(shí)體數(shù)據(jù)。

    見上文存儲(chǔ)過程部分

    11

    修改函數(shù)映射

    在此方案中,在存儲(chǔ)模型中定義用于插入、更新和刪除數(shù)據(jù)的存儲(chǔ)過程。這些函數(shù)是為實(shí)體類型定義的,以便為特定實(shí)體類型提供更新功能。

    見上文存儲(chǔ)過程部分

    12

    定義查詢映射

    在此方案中,在存儲(chǔ)模型中定義表示數(shù)據(jù)源中的表的查詢。在映射到 SQL Server 數(shù)據(jù)庫時(shí),查詢以數(shù)據(jù)源的本機(jī)查詢語言(如 Transact-SQL)表示。此 DefiningQuery 元素映射到概念模型中的實(shí)體類型。查詢以特定于存儲(chǔ)的查詢語言進(jìn)行定義。

    上文EDM之SSDL部分最后詳細(xì)介紹了這種設(shè)計(jì)的相關(guān)問題

    13

    查詢視圖映射

    在此方案中,會(huì)在概念模型中的實(shí)體類型與存儲(chǔ)模型中的關(guān)系表之間定義只讀映射。此映射基于對存儲(chǔ)模型進(jìn)行的 Entity SQL 查詢定義。

    上文EDM之MSL中說明三對這種設(shè)計(jì)的相關(guān)問題有介紹。

    14

    AssociationSet 映射

    關(guān)聯(lián)定義實(shí)體之間的關(guān)系。在具有一對一或一對多關(guān)聯(lián)的簡單映射中,在概念模型中定義關(guān)系的關(guān)聯(lián)會(huì)映射到存儲(chǔ)模型中的關(guān)聯(lián)。還支持以下更高級的關(guān)聯(lián)集映射:

    多對多關(guān)聯(lián)。關(guān)聯(lián)的兩端都映射到存儲(chǔ)模型中的鏈接表。

    自關(guān)聯(lián)。此映射支持具有相同類型的兩個(gè)實(shí)體之間的關(guān)聯(lián),如一個(gè) Employee 與另一個(gè) Employee 之間的關(guān)聯(lián)。

    派生類型之間的關(guān)聯(lián)。此映射支持一個(gè)層次結(jié)構(gòu)中的派生類型與另一個(gè)層次結(jié)構(gòu)中的派生類型之間的關(guān)聯(lián)。

    ?

    Entity Framework的原理及使用方式

    ADO.NET Entity Framework操作數(shù)據(jù)庫的過程對用戶是透明的(當(dāng)然我們可以通過一些工具或方法了解發(fā)送到數(shù)據(jù)庫的SQL語句等)。我們唯一能做的是操作EDM,EDM會(huì)將這個(gè)操作請求發(fā)往數(shù)據(jù)庫。

    ????Entity Framework實(shí)現(xiàn)了一套類似于ADO.NET2.0中連接類(它們使用方式相同,均基于Provider模式)的被稱作EntityClient的類用來操作EDM。ADO.NET2.0的連接類是向數(shù)據(jù)庫發(fā)送SQL命令操作表或視圖,而EntityClient是向EDM發(fā)送EntitySQL操作Entity。EntityClient在EntityFramework中的作用是相當(dāng)重要的,所有發(fā)往EDM的操作都是經(jīng)過EntityClient,包括使用LINQ to Entity進(jìn)行的操作。

    各種使用方式總結(jié)

    ????上文提到對EDM的操作,首先通過一個(gè)圖來展現(xiàn)一下目前我們可用的操作的EDM的方式:

    ?

    這幾種訪問方式使用介紹如下:(部分示例代碼來源MSDN Magzine)

  • EntityClient+EntitySQL

    示例代碼:

  • string city = "London";

    using (EntityConnection cn = new EntityConnection("Name=Entities"))

    {

    cn.Open();

    EntityCommand cmd = cn.CreateCommand();

    cmd.CommandText = @"SELECT VALUE c FROM Entities.Customers AS c WHERE

    c.Address.City = @city";

    cmd.Parameters.AddWithValue("city", city);

    DbDataReader rdr = cmd.ExecuteReader(CommandBehavior.SequentialAccess);

    while (rdr.Read())

    Console.WriteLine(rdr["CompanyName"].ToString());

    rdr.Close();

    }

    ?

  • ObjectService+EntitySQL
  • 在有EntityClient+EntitySQL這種使用方式下,使用ObjectService+EntitySQL的方式是多此一舉,不會(huì)得到任何編輯時(shí)或運(yùn)行時(shí)的好處。在ObjectContext下使用EntitySQL的真正作用是將其與LINQ to Entity結(jié)合使用。具體可見下文所示。

    示例代碼:

    string city = "London";

    using (Entities entities = new Entities())

    {

    ObjectQuery<Customers> query = entities.CreateQuery<Customers>(

    "SELECT VALUE c FROM Customers AS c WHERE c.Address.City = @city",

    new ObjectParameter("city", city)

    );

    ?

    foreach (Customers c in query)

    Console.WriteLine(c.CompanyName);

    }

    ?

  • ObjectContext+LINQ( to Entity)

    方式一:

  • string city = "London";

    using (Entities entities = new Entities())

    {

    var query = from c in entities.Customers

    where c.Address.City == city

    select c;

    ?

    foreach (Customers c in query)

     Console.WriteLine(c.CompanyName);

    }

    ????方式二:

    string city = "London";

    using (Entities entities = new Entities())

    {

    var query = entities.Customers.Where(r => r.Address.City == city);

    ?

    foreach (Customers c in query)

     Console.WriteLine(c.CompanyName);

    }

    這兩段示例代碼中的entities.Customer的寫法隱式調(diào)用了2中示例的ObjectQuery<Customers>來進(jìn)行查詢(關(guān)于此可以參見EDM的設(shè)計(jì)器文件-xxx.designer.cs)。在方式二中的Where方法傳入的是一個(gè)Lambda表達(dá)式,你也可以傳入一條EntitySQL語句做參數(shù)來將LINQ與EntitySQL結(jié)合使用。如下代碼演示其使用:

    string city = "London";

    using (Entities entities = new Entities())

    {

    var query = entities.Customers.Where("r.Address.City = '"+city+"'");

    ?

    foreach (Customers c in query)

     Console.WriteLine(c.CompanyName);

    }

    使用技巧及需要注意的問題

    這也是上文提到的在ObjectContext下使用EntitySQL的一個(gè)主要作用,上面的例子比較簡單可能看不到這樣使用的優(yōu)勢,但是如下兩種情況下使用EntitySQL可能是最好的選擇。

  • 動(dòng)態(tài)構(gòu)建查詢條件
    當(dāng)查詢條件的個(gè)數(shù)固定時(shí),我們也可以采用羅列多個(gè)Where擴(kuò)展方法的形式,如下:

    ObjectQuery.Where(LambdaExpression1) .Where(LambdaExpression2)…

    但是當(dāng)這個(gè)條件的存在與否需要在運(yùn)行時(shí)判斷時(shí),我們只能通過組合字符串來得到這個(gè)條件,我們可以將條件組合為EntitySQL并傳遞給Where()方法。

  • 數(shù)據(jù)庫模糊查詢

    下面代碼演示使用EntitySQL的like完成模糊查詢:

  • context.Customer.Where("it.CustomerID LIKE @CustomerID", new System.Data.Objects.ObjectParameter("CustomerID","%V%"));

    這個(gè)并不是只能使用EntitySQL來實(shí)現(xiàn),LINQ to Entity也可以很容易完成。如下代碼:

    context.Customer.Where(r => r.CustomerID.Contains("V"));

    同理,"V%"、"%V"可以分別使用StartsWith()與EndsWith()函數(shù)實(shí)現(xiàn)。

    ?

    ????使用LINQ to Entity需要注意的一個(gè)方面是,在完成查詢得到需要的結(jié)果后使用ToList或ToArray方法將結(jié)果轉(zhuǎn)變?yōu)閮?nèi)存中的對象,然后使用LINQ to Objects來處理,否則處在Entity Framework的聯(lián)機(jī)模式下對性能有很大的影響。

    ?

    幾種方法的性能分析及使用選擇

    首先用下圖來說明一個(gè)執(zhí)行過程。

    ????圖中所示表達(dá)的意思已經(jīng)非常清楚,稍加解釋的是,無論是通過EntityClient直接提供給Entity Client Data Provider的Entity SQL還是通過ObjectService傳遞的Entity SQL(或是LINQ to Entity),都在Entity Client Data Provider中被解釋為相應(yīng)的Command Tree,并進(jìn)一步解釋為對應(yīng)數(shù)據(jù)庫的SQL。這樣來看使用LINQ to Entity與Entity SQL的效率應(yīng)該差不多,但是還有一個(gè)問題,那就是EntitySQL所轉(zhuǎn)換的最終SQL可能要比LINQ to Entity生成的SQL效率高,這在一定程度上使兩者效率差增大,但是LINQ to Entity有其它技術(shù)無法比擬的好處,那就是它的強(qiáng)類型特性,編輯時(shí)智能感知提醒,編譯時(shí)發(fā)現(xiàn)錯(cuò)誤,這都是在一個(gè)大型項(xiàng)目中所需要的。雖然現(xiàn)在也有了調(diào)試EntitySQL的工具,但其與強(qiáng)類型的LINQ to Entity還是有很大差距。

    ????另外在ObjectService與直接使用EntityClient問題的選擇上。如果你想更靈活的控制查詢過程,或者進(jìn)行臨時(shí)查詢建議選擇EntityCLient,如果是操作數(shù)據(jù)那只能采用ObjectService。

    ?

    上文總結(jié)了各種操作EDM的方式,下面引用MSDN的一個(gè)對這幾種技術(shù)進(jìn)行比較的表格:

    ??

    EntityClient 和實(shí)體 SQL

    對象服務(wù)和實(shí)體 SQL

    對象服務(wù)和 LINQ

    定向到 EntityClient 提供程序

    適合臨時(shí)查詢

    可直接發(fā)出 DML

    強(qiáng)類型化

    可將實(shí)體作為結(jié)果返回

    通過這個(gè)表可以很好對某一場合下應(yīng)該選擇的技術(shù)進(jìn)行判斷。EntityClient 和實(shí)體 SQL可以進(jìn)行最大的控制,而使用LINQ to Entity可以獲得最佳的編輯時(shí)支持。

    ?

    其它操作EDM的方式

    通過EdmGen更靈活的控制EDM

    在.NET Framework 3.5的文件夾下有一個(gè)名為EdmGen的工具,Visual Studio的實(shí)體設(shè)計(jì)器就是調(diào)用這個(gè)工具來完成EDM的生成等操作。通過直接使用這個(gè)工具的命令行選項(xiàng)我們可以進(jìn)行更多的控制。

    這個(gè)命令的參數(shù)及作用如下:

    EdmGen 選項(xiàng)

    /mode:EntityClassGeneration 從 csdl 文件生成對象

    /mode:FromSsdlGeneration 從 ssdl 文件生成 msl、csdl 和對象

    /mode:ValidateArtifacts 驗(yàn)證 ssdl、msl 和 csdl 文件

    /mode:ViewGeneration 從 ssdl、msl 和 csdl 文件生成映射視圖

    /mode:FullGeneration 從數(shù)據(jù)庫生成 ssdl、msl、csdl 和對象

    /project:<字符串> 用于所有項(xiàng)目文件的基名稱 (短格式: /p)

    /provider:<字符串> 用于 ssdl 生成的 Ado.Net 數(shù)據(jù)提供程序的名稱。(短格式: /prov)

    /connectionstring:<連接字符串> 您要連接到的數(shù)據(jù)庫的連接字符串 (短格式: /c)

    /incsdl:<文件> 從中讀取概念模型的文件

    /refcsdl:<文件> 包含 /incsdl 文件所依賴的類型的 csdl 文件

    /inmsl:<文件> 從中讀取映射的文件

    /inssdl:<文件> 從中讀取存儲(chǔ)模型的文件

    /outcsdl:<文件> 將生成的概念模型寫入到其中的文件

    /outmsl:<文件> 將生成的映射寫入到其中的文件

    /outssdl:<文件> 將生成的存儲(chǔ)模型寫入到其中的文件

    /outobjectlayer:<文件> 將生成的對象層寫入到其中的文件

    /outviews:<文件> 將預(yù)生成的視圖對象寫入到其中的文件

    /language:CSharp 使用 C# 語言生成代碼

    /language:VB 使用 VB 語言生成代碼

    /namespace:<字符串> 用于概念模型類型的命名空間名稱

    /entitycontainer:<字符串> 用于概念模型中的 EntityContainer 的名稱

    /help 顯示用法信息 (短格式: /?)

    /nologo 取消顯示版權(quán)消息

    ?

    使用示例:

    從 Northwind 示例數(shù)據(jù)庫生成完整 Entity Model。

    EdmGen /mode:FullGeneration /project:Northwind /provider:System.Data.SqlClient /connectionstring:"server=.\sqlexpress;integrated security=true; database=northwind"

    從 ssdl 文件開始生成 Entity Model。

    EdmGen /mode:FromSSDLGeneration /inssdl:Northwind.ssdl /project:Northwind

    驗(yàn)證 Entity Model。

    EdmGen /mode:ValidateArtifacts /inssdl:Northwind.ssdl /inmsl:Northwind.msl /incsdl:Northwind.csdl

    ?

    為什么要使用Entity Framework,限制條件及當(dāng)前版本框架的問題

    • 優(yōu)勢

    通過對比上面圖4與圖2、圖3我們可以很清楚的看到使用Entity Framework一個(gè)很大的好處,我們可以把實(shí)體類的定義由一個(gè)單獨(dú)的項(xiàng)目使用C# class完成這樣一種設(shè)計(jì)方式轉(zhuǎn)變?yōu)槭褂脁ml文件定義并集成到數(shù)據(jù)訪問層。

    ????在以往要在一個(gè)項(xiàng)目中動(dòng)態(tài)創(chuàng)建實(shí)體,我所知的方法是把要添加的實(shí)體放入一個(gè)程序集,然后通過反射加載程序集。現(xiàn)在可以通過動(dòng)態(tài)更改EDM的方法來增加實(shí)體并將其映射到數(shù)據(jù)庫,后者是以前無法實(shí)現(xiàn)的。

    ????便于更改數(shù)據(jù)庫,當(dāng)更換數(shù)據(jù)庫后,只需修改SSDL的定義,(如果數(shù)據(jù)庫的表明有變動(dòng),也只需多修改MSL),對CSDL沒有任何影響,從而也不需要對程序的BLL等上層部分做任何改動(dòng)。

    • 條件

    要想讓一個(gè)數(shù)據(jù)庫支持Entity Framework,一個(gè)必要條件就是該數(shù)據(jù)庫需提供相應(yīng)的Entity Client Data Provider,這樣才能將Entity SQL轉(zhuǎn)換為針對此數(shù)據(jù)此數(shù)據(jù)庫的SQL并交由ADO.NET來執(zhí)行。當(dāng)然該數(shù)據(jù)庫還需要提供ADO.NET Data Provider。

    • 缺陷

    Entity Framework技術(shù)的效率問題是其幾乎唯一一個(gè)稍有不足之處。首先其將EntitySQL轉(zhuǎn)換為SQL的方式屬于解釋性轉(zhuǎn)換,性能較差。另外Entity Framework在每次應(yīng)用啟動(dòng)時(shí)需要讀取EDM,這個(gè)過程較慢(但在后續(xù)操作時(shí),就不再存在這個(gè)問題)。

    ?

    EDM中的DML

    由于當(dāng)前的EntitySQL不支持DML操作,所以當(dāng)前版本的Entity Framework的插入、更新及刪除操作需要通過Object Service來完成。在EDM的設(shè)計(jì)器文件xxx.designer.cs中自動(dòng)生成了一些簽名為

    void AddToEntity(EntityType entity)

    的方法。我們只需要新建一個(gè)實(shí)體對象并調(diào)用這個(gè)方法添加實(shí)體即可。注意這個(gè)函數(shù)內(nèi)部調(diào)用

    ????entities.AddObject("EntitySetName", entity);

    最后調(diào)用entities.SaveChanges()方法將修改保存回?cái)?shù)據(jù)庫,這是所有三種更新操作所需的。更新與刪除操作都需要先使用ObjectService定位操作的實(shí)體對象,更新操作直接使用賦值運(yùn)算符,刪除操作則調(diào)用

    ????entites.DeleteObject(object o);

    方法。之后調(diào)用entities.SaveChanges()方法保存,這個(gè)過程簡單,不再贅述。

    ?

    含有Association的EDM的使用

    ????當(dāng)前版本的Entity Framework不支持自動(dòng)延遲加載,所有當(dāng)前未使用的關(guān)系中的相關(guān)實(shí)體默認(rèn)按不加載處理,當(dāng)我們需要通過關(guān)系獲取一個(gè)實(shí)體對象時(shí),我們可以采用兩種方法:

  • 顯示加載
    實(shí)體框架針對 EntityReference 類的每個(gè)實(shí)例提供一個(gè) Load 方法。此方法可用于顯式加載與另一實(shí)體相關(guān)的一個(gè)集合。我們只需在訪問關(guān)系中實(shí)體之前調(diào)用其Load即可,當(dāng)然提前判斷該實(shí)體是否已經(jīng)加載是一種比較好的實(shí)踐。如下代碼所示
  • using (Entities entities = new Entities())

    {

    var query = (from o in entities.Orders

    where o.Customers.CustomerID == "ALFKI"

    select o);

    foreach (Orders order in query)

    {

    if (!order.CustomersReference.IsLoaded)

    order.CustomersReference.Load();

    Console.WriteLine(order.OrderID + " --- " +

    order.Customers.CompanyName);

    }

    }

  • 預(yù)先加載

    先看代碼示例

  • using (Entities entities = new Entities())

    {

    var query = (from o in entities.Orders.Include("Customers")

    where o.ShipCountry == "USA"

    select o);

    ?

    foreach (Orders order in query)

    Console.WriteLine(order.OrderID + " --- " +

    order.Customers.CompanyName);

    }

    查詢中針對 Orders 實(shí)體調(diào)用的 Include 方法接受了一個(gè)參數(shù),該參數(shù)在本示例中將要求查詢不僅要檢索 Orders,而且還要檢索相關(guān)的 Customers。這將生成單個(gè) SQL 語句,它會(huì)加載滿足 LINQ 查詢條件的所有 Order 和 Customer。

    兩種加載關(guān)系實(shí)體的方式的選擇根據(jù):如果針對關(guān)系數(shù)據(jù)你只需做一到兩次查詢,則使用顯示加載更高效,如果要持續(xù)訪問關(guān)系實(shí)體中數(shù)據(jù),則使用預(yù)先加載。

    ?

    關(guān)系下的添加,更新與刪除與上述操作基本相同,唯一需要注意的是刪除操作不支持級聯(lián)刪除,需要手工遍歷所有的相關(guān)項(xiàng)并將其一一刪除。注意這里刪除操作不能使用foreach來遍歷需要?jiǎng)h除的關(guān)系實(shí)體。取而代之的有兩種方法:

  • while法
  • while (result.Order_Details.Count > 0)

    {

    // 刪除操作

    }

  • ToList法(以非聯(lián)機(jī)方式操作)

    var items = result.Order_Details.ToList();

    foreach (var item in items)

    {

    // 刪除操作

    }

  • 最新補(bǔ)充

    Entity Framework在開發(fā)中的應(yīng)用 – Entity Framework與控件

    .NET Framework提供了許多xxxDataSource控件,如SqlDataSource,ObjectDataSource等,這些數(shù)據(jù)源控件大大方便了我們的數(shù)據(jù)綁定操作。不幸的是目前還沒有針對Entity Framework的數(shù)據(jù)源控件發(fā)布,但是將數(shù)據(jù)綁定到諸如ListBox,Grrdview或DetailsView控件也是很簡單的。這源于使用ObjectContext操作返回的IQueryable<T>對象或是使用EntityClient查詢返回的ObjectQuery對象都實(shí)現(xiàn)了IEnumerable接口。這樣很容易將這些數(shù)據(jù)綁定到數(shù)據(jù)顯示控件。更新操作可以按上文所述在相應(yīng)的時(shí)間處理函數(shù)中寫更新EDM的程序即可。

    Entity Framework的鏈接字符串

    ????默認(rèn)情況下(Visual Studio對Entity Framework數(shù)據(jù)項(xiàng)目的默認(rèn)設(shè)置),EDM這個(gè)XML文件被作為資源在編譯時(shí)嵌入到程序集中。這種情況下當(dāng)更改EDM后需要重新編譯這個(gè)程序集才能使更改生效。通過更改項(xiàng)目屬性也可以讓EDM作為三個(gè)獨(dú)立的XML文件存在于項(xiàng)目中。為了讓應(yīng)用程序可以找到EDM(無論其以什么方式存儲(chǔ))需要一個(gè)鏈接字符串來指示EDM所在的位置。實(shí)體模型設(shè)計(jì)器生成的鏈接字符串如下所示:

    <add name="ASSEntities"

    connectionString="

    metadata=res://*/ass.csdl|

    res://*/ass.ssdl|

    res://*/ass.msl;

    provider=System.Data.SqlClient;

    provider connection string=&quot;Data Source=(local);Initial Catalog=ASS;Integrated Security=True;MultipleActiveResultSets=True&quot;"

    providerName="System.Data.EntityClient" />

    http://msdn.microsoft.com/zh-cn/library/cc716756.aspx

    關(guān)鍵的一點(diǎn)應(yīng)用程序是怎樣找到這個(gè)字符串的,對于使用EntityClient的情況,可以直接將連接字符串賦給EntityConnection的ConnectionString屬性,另外對于使用ObjectContext,其可以自動(dòng)由配置文件檢索這個(gè)連接字符串。

    轉(zhuǎn)載于:https://www.cnblogs.com/vebest/archive/2010/06/03/1750685.html

    總結(jié)

    以上是生活随笔為你收集整理的[(转)hystar整理]Entity Framework 教程的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。