Entity Framework 學習

 

ADO.NET 實體框架概述sql

新版本中的 ADO.NET 以新實體框架爲特點。它使開發人員能夠經過對象模型(而不是邏輯/關係數據模型)專一於數據。實體框架有助於將邏輯數據架構抽象爲概念模型,而且容許以多種方式經過對象服務和名爲「EntityClient」的新數據提供程序與概念模型交互。數據庫

實體框架使用概念層(ConceptualModels)、映射層(Mappings)和邏輯層(StorageModels)將邏輯數據庫結構抽象化。EntityClient 的備選項是對象服務。具體地說,實體框架中的對象服務有助於減小開發人員須要編寫的數據訪問代碼的數量。編程

 

實體框架組件緩存

實體框架使開發人員能夠編寫更少的數據訪問代碼,減小維護,將數據結構抽象化爲更易於開展業務(標準化程度較低)的方式,而且有利於數據的持久性。當與 LINQ to Entities結合使用時,因爲實體框架從概念模型中生成強類型化類,還有助於下降編譯時錯誤的數量。服務器

實體框架生成開發人員可以依據其編寫代碼的概念模型。使用名爲「EntityClient」的新數據提供程序和名爲「Entity SQL」的新語言(相似於 T-SQL)能夠直接與該模型交互。EntityClient 具備與熟悉的 ADO.NET 對象相似的模型,使用 EntityConnection 和 EntityCommand 對象返回 DbDataReader。開發人員的另外一種方法是經過具備Entity SQL 的 ObjectQuery 對象或 LINQ to Entities 來使用對象服務。對象服務使開發人員能夠利用概念模型的生成類,這些生成類提供了強類型化對象和持久性等特性(請參見圖 1)。網絡

clip_image002[6]

圖 1 實體框架概述數據結構

這些數據訪問技術使開發人員能夠與 EDM 的概念實體交互。EDM 的各個層以 XML 文件形式存在;目前能夠經過手動方式(或使用 Visual Studio 中的嚮導)使用命令行工具 (EDMGEN.EXE) 生成 EDM。架構

 

實體數據模型併發

實體框架的核心位於其模型中。實體框架支持表示數據庫中的關係架構的邏輯存儲模型。關係數據庫一般存儲數據的方式與應用程序使用數據的方式不一樣。一般,這會迫使開發人員按照數據庫包含數據的結構檢索數據。所以,開發人員一般將數據加載到更適合處理業務規則的業務實體中。在本示例中,以邏輯模型表示關係數據庫的構架,業務實體表示概念模型。實體框架使用映射層在模型之間搭建了橋樑。所以,實體框架的模型中有三個處於活動狀態的層:app

· 概念層

· 映射層

· 邏輯層

這三層容許將數據從關係數據庫映射到更加面向對象的業務模型。實體框架提供了使用 XML 文件定義這些層的方法。它還基於概念模型的架構生成了一系列類。能夠針對這些類進行編程以直接與數據交互。這提供了抽象級別,所以開發人員能夠針對概念模型而不是關係模型進行編程。實體框架可將針對概念模型編碼的全部命令映射到邏輯模型中(請參見圖 2)。

clip_image004[4]

圖 2 設計實體數據模型 (單擊該圖像得到較大視圖)

概念模型是使用概念架構定義語言 (CSDL) 在 XML 文件中定義的。CSDL 定義應用程序的業務層所知道的實體和關係。邏輯模型(表示數據庫架構)是使用存儲架構定義語言 (SSDL) 在 XML 文件中定義的。例如,您可能在概念模型中有一個實體,該實體實際上從數據庫的多個表中派生其數據。概念模型和邏輯模型可按一對一的關係來關聯實體。然而,EDM 的功能是它沒必要以一對一的方式連接實體。映射層(是使用映射架構語言 (MSL) 定義的)實現其餘兩層彼此之間的映射。此映射使開發人員能夠針對概念模型編寫代碼,並將這些指令映射到邏輯模型。

 

生成實體數據模型

能夠將數據庫做爲起點生成 EDM。而後,能夠手動修改 XML(或者可能使用 Visual Studio 未來版本中可能提供的模型工具)。將 ADO.NET EDM 添加到項目後,嚮導會指導您完成建立 EDM 的過程。

第一步、建立解決方案「EntityFrameworkTest」和控制檯應用程序「EFProjectCA」。

clip_image006

第二步、添加「ADO.NET實體數據模型」,命名爲"NorthWindEF.edmx"。

clip_image008

接着選擇「從數據庫生成」,若是後期採用POCO開發模式,能夠選擇」空模型「。

clip_image010

clip_image012

clip_image014

clip_image016

clip_image018

到這裏就建立成功了。NorthWindEF.edmx包含了CSDL、SSDL、MSL,咱們能夠經過記事本查看它的結構,也能夠複製一份,把擴展名改成xml,在VS2010中打開。

clip_image020

 

分析 CSDL

駐留在 CSDL 文件中的元數據包含一系列實體和關係,其中實體由 EntityType 元素表示,關係由 Association 元素表示。實體包含一系列用於定義實體的標量屬性。Key 屬性指示對實體很關鍵的屬性。複合關鍵字經過用空格分隔每一個屬性名來表示。實體還能夠包含名爲「NavigationProperty」的一種特殊類型的屬性。這定義瞭如何按照關聯從一個實體導航到另外一個實體。

<EntityType Name="Customers">

<Key>

<PropertyRef Name="CustomerID" />

</Key>

<Property Name="CustomerID" Type="String" Nullable="false" MaxLength="5" Unicode="true" FixedLength="true" />

<Property Name="CompanyName" Type="String" Nullable="false" MaxLength="40" Unicode="true" FixedLength="false" />

<Property Name="ContactName" Type="String" MaxLength="30" Unicode="true" FixedLength="false" />

...

<NavigationProperty Name="Orders" Relationship="NorthwindModel.FK_Orders_Customers" FromRole="Customers" ToRole="Orders" />

<NavigationProperty Name="CustomerDemographics" Relationship="NorthwindModel.CustomerCustomerDemo" FromRole="Customers" ToRole="CustomerDemographics" />

</EntityType>

如下 CSDL 片斷定義了 Customer 及其 Orders 之間的 AssociationSet :

<AssociationSet Name="FK_Orders_Customers" Association="NorthwindModel.FK_Orders_Customers">

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

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

</AssociationSet>

AssociationSet 的 End 元素表示關聯的參與者。在本示例中,一個 Customers 實體與一個 Orders 實體相關聯。根據多重性定義,一個 Customers 實體還能夠與任意數量的 Orders 實體相關聯。

EntityType 和 Association 元素定義域實體和關係的類型,而 EntitySet 和 AssociationSet 元素定義實體和關係的做用域。邏輯上應組合到一塊兒的全部「集」都包含在 EntityContainer 元素內。

下面的 CSDL 片斷顯示了 EntityContainer 及其部份內容:

<EntityContainer Name="NorthwindEntities" annotation:LazyLoadingEnabled="true">

<EntitySet Name="Categories" EntityType="NorthwindModel.Categories" />

<EntitySet Name="CustomerDemographics" EntityType="NorthwindModel.CustomerDemographics" />

<EntitySet Name="Customers" EntityType="NorthwindModel.Customers" />

...

<AssociationSet Name="FK_Products_Categories" Association="NorthwindModel.FK_Products_Categories">

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

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

</AssociationSet>

<AssociationSet Name="FK_Orders_Customers" Association="NorthwindModel.FK_Orders_Customers">

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

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

</AssociationSet>

...

</AssociationSet>

</EntityContainer>

 

映射到存儲

SSDL 文件定義了數據庫中關係數據的結構。在本例中,它還使用了 EntityType 和 Association XML 元素來分別聲明存在於數據庫中的表和外鍵的結構。SSDL 文件的命名空間是基於 EDM 中所用數據庫的名稱而設置的,而其 EntityContainer 元素是以數據庫架構命名的。EntityContainer 包含一系列 EntitySet 和 AssociationSet 元素,這些元素聲明由 EntityType 和 AssociationType 表示的表和關係的實例。對於 SSDL 文件中的每一個 EntitySet,數據庫中均有一個與之對應的表。

若是從數據庫中生成 EDM 而且未對 CSDL 和 SSDL 文件進行修改就當即將其打開,則您會發現這些文件極其類似。這是由於模型是直接從數據庫生成的,所以概念模型直接映射到了邏輯存儲。MSL 文件包含從 CSDL 到 SSDL 的直接映射。全部針對 EDM 編寫的查詢均將轉換爲生成的 SQL 命令。實體框架還支持使用存儲過程而不是生成的 SQL 查詢。

EntityContainerMapping 元素用於將模型 (CSDL) 映射到存儲 (SSDL)。StorageEntityContainer 屬性表示存儲中 EntityContainer 的名稱,而 CdmEntityContainer 屬性表示模型中與之相對應的 EntityContainer。將模型的 EntitySet 映射到存儲的 EntitySet 須要 EntitySetMapping 元素。TypeName 屬性定義模型中 EntitySet 的名稱,而 StoreEntitySet 屬性定義存儲中與之相對應的 EntitySet 的名稱。經過 ScalarProperty 元素可將模型中的每一個屬性映射到存儲。

<EntitySetMapping Name="Products">

<EntityTypeMapping TypeName="NorthwindModel.Products">

<MappingFragment StoreEntitySet="Products">

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

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

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

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

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

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

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

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

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

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

</MappingFragment>

</EntityTypeMapping>

</EntitySetMapping>

 

使用 EntityClient

可經過三種不一樣機制中的任意一種實現對實體框架的概念模型的訪問(請參見圖 1)。在此,我將介紹 EntityClient,即新的 .NET 數據提供程序。

當 EntityClient 使用本身的名爲「Entity SQL」的基於文本的語言與概念模型通訊時,會將其從邏輯存儲中提取出來。全部使用 EntityClient 執行的Entity SQL 查詢均被編譯成發送到存儲的命令樹。查詢從概念模型的Entity SQL 到存儲的向下轉換由實體框架處理。

EntityClient 中的類與常見的 ADO.NET 提供程序中的類類似。例如,使用 EntityCommand 對象執行 EntityClient 查詢,這須要 EntityConnection 對象鏈接到 EDM。當 EntityClient 與 EDM 中的實體交互時,EntityClient 不返回實體的實例而返回 DbDataReader 對象中的全部結果。EntityClient 能夠返回一組標準行和列,也能夠經過 DbDataReader 返回更復雜的分層數據的表示形式。

示例使用 EntityClient 鏈接到概念模型並檢索來自倫敦的客戶列表。EntityConnection 能夠接受概念層的完整鏈接字符串或 App.Config 文件中鏈接字符串的名稱。鏈接字符串包含元數據文件(CSDL、MSL 和 SSDL 文件)列表,以及存儲的專用於數據庫的鏈接字符串信息。

using System.Data;

using System.Data.EntityClient;

using System.Configuration;

...

//string connStr = System.Configuration.ConfigurationManager.ConnectionStrings["NorthwindEntities"].ConnectionString;

//CSharpTestEntities edm = new CSharpTestEntities();

//string connStr = edm.Connection.ConnectionString;

string connStr = "name = NorthwindEntities"; //使用三種方法獲取鏈接字符串

using (EntityConnection conn = new EntityConnection(connStr))

{

string sqlStr = " SELECT VALUE c FROM NorthwindEntities.Customers AS c";

conn.Open();

EntityCommand ecmd = new EntityCommand(sqlStr, conn);

//ExecuteDbDataReader、ExecuteNonQuery 、ExecuteReader 、ExecuteScalar等

EntityDataReader edr = ecmd.ExecuteReader(CommandBehavior.SequentialAccess);

while (edr.Read())

{

Console.WriteLine(edr["CompanyName"]);

}

Console.WriteLine(ecmd.ToTraceString());

}

Console.Read();

 

使用對象服務

與由 EDM 表示的數據進行交互的另外一種方法是使用對象服務。經過對象服務,能夠加載對象和導航在 EDM 中定義的任何關係。如圖 1 所示,對象服務使用 EntityClient 來獲取數據。對象服務增添了身份解析,使用 DataSet 時,該身份解析是手動過程。它還提供了對象持久性和事件的跟蹤更改以容許顯式加載和保存。這將縮短與服務器的往返路程。

對象服務容許直接返回對象列表(便可同時返回投影和定義的實體)。例如,使用對象服務,您能夠按 EDM 中的定義檢索 List<Customers>。能夠檢查 Customers 對象,更改值,而後將數據再次保存到數據庫中。

若是將投影與對象服務結合使用,則返回的數據將是不可更新的對象。因爲投影返回實體的特定屬性而不是整個實體,對象服務沒法將投影數據的更新再次保存到數據庫中。若是您要更新數據,更好的選擇是返回整個實體而不是使用投影。

您可使用對象服務以使用Entity SQL 執行查詢,也可使用 LINQ to Entities 編寫查詢。下面的示例演示瞭如何使用對象服務和Entity SQL 進行查詢以檢索 Customers 列表:

using System.Data.Objects;

...

using (var edm = new NorthwindEntities())

{

string esql = "select value c from NorthwindEntities.Customers as c order by c.CustomerID limit 10";

ObjectQuery<Customers> query = edm.CreateQuery<Customers>(esql);

ObjectResult<Customers> results = query.Execute(MergeOption.NoTracking);

foreach (Customers c in results)

Console.WriteLine(c.CustomerID + ":" + c.CompanyName);

Console.WriteLine(query.ToTraceString());

}

在 EDM 中,EntityContainer 由從 ObjectContext(在本示例中爲 northwindContext)繼承的類表示。ObjectContext 類實施 ObjectQuery<T> 接口,從而使其可使用Entity SQL 或 LINQ 建立查詢。

CreateQuery 方法接受參數化的Entity SQL 語句,該語句定義了將檢索 Customers 實體列表的查詢。經過使用 foreach 語句對 ObjectQuery<Customers> 進行迭代時將執行做用於數據庫的實際 SQL 語句。

 

使用 LINQ to Entities

能夠在Entity SQL 中編寫動態查詢,並與對象服務一塊兒使用來與 EDM 實體交互。可是,實體框架還能夠與使用 LINQ to Entities 強類型化 EDM 類結合使用。例如,在剛纔顯示的示例中,能夠將使用對象服務和Entity SQL 進行查詢修改成使用 LINQ to Entities 進行查詢,以下所示:

ObjectQuery<Customers> customersList = edm.Customers;

IQueryable<Customers> customersResult = from customers in customersList

where customers.City == "London"

select customers;

foreach (Customers c in customersResult)

Console.WriteLine(c.CustomerID + ":" + c.CompanyName);

此代碼示例使用由 C# 3.0 支持的強類型化 LINQ 語法替代了Entity SQL 的全部基於文本的語法。

 

解釋 EntityClient 和對象服務之間的差別,並介紹將 LINQ 和 EntitySQL 與這些服務一塊兒使用的意義。可以使用 LINQ 獲取實體時爲何要使用實體 SQL?

介紹可用於與 EDM 進行交互的三種主要技術:

· 使用 EntityClient 提供程序編寫 EntitySQL 查詢

· 使用對象服務編寫 EntitySQL 查詢

· 使用對象服務編寫 LINQ 查詢

以上每種技術都擁有共同的特徵;例如,都直接或間接使用 EntityClient 提供程序。可是,它們產生的結果以及得到這些結果的方式卻有所不一樣。

EntityClient 提供程序具備一系列對象,若是瞭解 ADO.NET 對象模型,則您應該熟悉這些對象。EntityConnection 用於鏈接到 EDM,EntityCommand 用於針對 EDM 發出查詢,而命令的結果則經過 DbDataReader 返回。不管是經過對象服務直接仍是間接使用 EntityClient,EntityClient 最終都會發出查詢並返回結果。

這使得問題再次擺上桌面,爲何有 LINQ 卻要使用 EntitySQL?答案在於每種技術的優缺點。

 

EntityClient + EntitySQL

深刻分析:實體框架數據加載

許多對象關係映射框架都支持如下兩種衆所周知的行爲,它們有助於編寫短時間「探測」代碼、改進應用程序使用數據庫的次數和數據傳輸量:

· 預先加載:每次程序須要操做一組相關對象時,都會在一個先期請求中從數據庫凍結整個圖。

· 延遲加載:當程序導航鏈接對象圖的屬性時自動從數據庫加載數據,此時可能屢次訪問存儲庫,但僅加載必需的項目。

爲遵循「無隱藏網絡往返操做」原則,實體框架放棄了自動化延遲加載。遍歷由代碼生成的類所組成的圖這一操做永遠不會針對存儲庫觸發查詢。實體框架代之以要求用戶代碼在使用以前明確凍結全部對象。

可隨時加載,但在每次要執行加載時需針對引用或集合調用稱爲 Load 的方法。實際上,經過干涉代碼生成過程或經過編寫本身的類,仍可實現隱式延遲加載。可是,更常見的方法是延遲加載而非僅隱藏往返操做。您必須瞭解,每次程序使用延遲加載時,都容易獲得一個包含不一致數據的圖。而且,若是程序不及時刷新已加載的數據,圖中的數據就可能會失效。

經過使用 EntityClient API 編寫代碼,可最精細地控制這三種技術。可建立 EntityConnection 來鏈接 EDM,以 EntitySQL 編寫一個查詢並使用 EntityCommand 執行該查詢,而後經過 DbDataReader 返回結果。此技術要精簡一些,省去了 LINQ 和對象服務提供的一些語法修飾。

EntitySQL 最大的優勢是其靈活性。基於字符串的語法有助於輕鬆地構建動態查詢。若是須要建立臨時查詢,它將很是有用。可是,這種靈活和精簡也使得只能經過 DbDataReader 返回結果。沒法使用 EntityClient 和 EntitySQL 從 EDM 返回純實體。DbDataReader 可供檢索並用於在知足 EntitySQL 查詢的行集合中執行迭代。

 

對象服務 + EntitySQL

另外一技術是使用對象服務並利用 EntitySQL 來執行查詢。從而再也不與 EntityClient 提供程序直接交互(儘管實際上它仍會與提供程序通訊)。使用 ObjectContext 和 ObjectQuery<T> 來針對 EDM 發出查詢。

此技術很是適合於發出臨時查詢(與第一種技術相同)。可是,它不是經過 DbDataReader 返回數據,將對象服務與 EntitySQL 一塊兒使用時可從 EDM 返回實體。所以,可牢靠地提供如下優勢:查詢靈活且返回最佳實體。可以使用此技術從 EDM 檢索實體,而後使用 ObjectContext 中的 SaveChanges 方法來更新實體。

 

對象服務 + LINQ

將對象服務 LINQ 一塊兒使用並不適合於臨時查詢,這一點與其餘技術不一樣。

所以,爲何有 LINQ 卻要使用實體 SQL?若是須要臨時查詢或但願建立比使用 LINQ 實現的查詢更加靈活的查詢,則應使用實體 SQL。不然,建議使用 LINQ 和對象服務,以即可受益於其強類型化以及返回實體和投影的功能。

如使用 LINQ 的強類型化語法,還可在設計時發現許多錯誤,沒必要等到運行應用程序時才發現。我很是喜歡這一功能——它使我能夠一心一意編寫代碼,沒必要經過執行構建和運行來找出錯誤。

ObjectContext 的做用是什麼? ObjectContext 是到對象服務的 EntityConnection 的通道。它經過底層 EntityConnection 提供對 EDM 的訪問。例如,可經過 ObjectContext 訪問實體,詢問 ObjectContext 以找出有關對象狀態的信息,以及使用 CreateQuery 方法建立 ObjectQuery<T> 查詢。

ObjectContext 的另外一目的是爲對象提供獲取數據庫條目更新信息的方法。例如,可以使用 ObjectContext 方法來將實體添加到 ObjectContext、刪除實體、操做實體以及最終將實體更改保存到數據庫(經過 SaveChanges 方法)。

 

結束語

clip_image002

System.Data.Objects (System.Data.Entity.dll)

該命名空間包含一些類,用於提供對對象服務的核心功能的訪問。 這些類使您能夠藉由做爲實體類型實例的強類型 CLR 對象來查詢、插入、更新和刪除數據。 對象服務支持針對實體數據模型 (EDM) 中定義的類型進行的語言集成查詢 (LINQ)  ESQL 查詢。對象服務將返回的數據具體化爲對象,並將對象更改傳播回數據源。 它還提供了用於跟蹤更改、將對象綁定到控件以及處理併發問題的功能。

 

 EntityClient 提供程序的基礎上,實體框架添加了另外一組抽象,以便容許針對對象而非 EntityClient 返回的非類型化數據記錄進行開發。這就是一般被認爲是 ORM 的層,它能夠生成在數據模型中所定義類型的 CLR 實例並容許開發人員使用 LINQ  ESQL 查詢這些對象。它也剛好是當初衆多開發人員在市場中尋找可用的 ORM 技術時最能吸引他們眼球的實體框架層。

 

對象服務層的高級功能是接受來自應用程序的 ESQL  LINQ 查詢,而後將查詢表達式傳遞給下面的 EntityClient 並返回IEnumerable<T>。可是,通過深刻的分析後您會發現,對象服務層的中心是表明應用程序與底層數據存儲之間的交互會話的ObjectContext

 

ObjectContext 是開發人員在查詢、添加和刪除其實體實例以及將新狀態保存回數據庫時用到的主要構造。

 

若是使用對象服務,則對開發人員而言,跟蹤內存中對象所發生的更改的流程以及將這些更改保存回數據庫的流程都會獲得簡化。對象服務使用 ObjectStateManager 不但會跟蹤內存中實例的當前狀態,還會跟蹤每一個實例從存儲庫中檢索出來時的初始狀態,從而使實體框架能夠在將數據推送回數據庫時應用最優的併發操做。經過對 ObjectContext 調用 SaveChanges 方法,能夠輕鬆地保存所跟蹤的更改並將其推送回數據存儲庫。

 

注:http://msdn.microsoft.com/zh-cn/library/system.data.objects.aspx

 

ObjectContext

ObjectContext 封裝 .NET Framework 和數據庫之間的鏈接。此類用做建立讀取更新刪除操做的網關。 它是以對象(這些對象是概念模型中定義的實體類型的實例)的形式與數據進行交互的主要類。

 

ObjectContext 類的實例封裝如下內容:

· 數據庫的鏈接,以 EntityConnection 對象的形式封裝。

· 描述該模型的元數據,以 MetadataWorkspace 對象的形式封裝。

· 用於管理緩存中持久保存的對象的 ObjectStateManager 對象。

 

成員參考:http://msdn.microsoft.com/zh-cn/library/system.data.objects.objectcontext_members.aspx

 

構造函數

ObjectContext(EntityConnection) :使用給定鏈接初始化 ObjectContext 類的新實例。 在構造過程當中,從 EntityConnection 對象提取元數據工做區。

ObjectContext(String) :使用給定的鏈接字符串和默認的實體容器名稱初始化 ObjectContext 類的新實例。

 

經常使用方法

AcceptAllChanges:接受在對象上下文中對對象所作的全部更改。

AddObject :將對象添加到對象上下文。

ApplyCurrentValues<TEntity> :將標量值從提供的對象複製到 ObjectContext 中具備相同鍵的對象中。

ApplyOriginalValues<TEntity> :將標量值從提供的對象複製到 ObjectContext 中具備相同鍵的對象的原始值集中。

Attach :在對象具備實體鍵時將對象或對象圖附加到對象上下文。

AttachTo :將對象或對象圖附加到特定實體集中的對象上下文。

CreateDatabase :使用當前數據源鏈接和 StoreItemCollection 中的元數據建立數據庫。

CreateDatabaseScript :生成數據定義語言 (DDL) 腳本,該腳本爲 StoreItemCollection 中的元數據建立架構對象(表、主鍵、外鍵)。

CreateEntityKey :爲特定對象建立實體鍵,若是實體鍵已存在,則返回該鍵。

CreateObject<T> :建立並返回所請求的類型的實例。

CreateObjectSet<TEntity>() :建立新的 ObjectSet<TEntity> 實例,該實例用於查詢、添加、修改和刪除指定實體類型的對象。

CreateObjectSet<TEntity>(String) :建立新的 ObjectSet<TEntity> 實例,該實例用於查詢、添加、修改和刪除具備指定類型和指定實體集名稱的對象。

CreateProxyTypes :爲提供的枚舉中的每一個類型生成可用於 Entity Framework 的等效類型。

CreateQuery<T> :使用指定查詢字符串在當前對象上下文中建立 ObjectQuery<T>

DatabaseExists :檢查在當前數據源鏈接中指定爲數據庫的數據庫是否在數據源上存在。

DeleteDatabase :刪除在當前數據源鏈接中指定爲數據庫的數據庫。

DeleteObject :將對象標記爲待刪除。

Detach :從對象上下文移除對象。

DetectChanges :確保 ObjectStateEntry 更改與由 ObjectStateManager 跟蹤的全部對象中的更改進行同步。

Equals(Object) :肯定指定的 Object 是否等於當前的 Object (繼承自 Object。)

ExecuteFunction(String, ObjectParameter[]) :執行在數據源中定義並在概念模型中表示的存儲過程或函數,丟棄該函數返回的任何結果,並返回執行該函數影響的行數。

ExecuteFunction<TElement>(String, ObjectParameter[]) :使用指定的參數,執行在數據源中定義並在概念模型中映射的存儲過程或函數。 返回類型化的 ObjectResult<T>

ExecuteFunction<TElement>(String, MergeOption, ObjectParameter[]) :使用指定的參數和合並選項,執行在數據源中定義並在概念模型中表示的給定存儲過程或函數。 返回類型化的 ObjectResult<T>

ExecuteStoreCommand :利用現有鏈接對數據源直接執行任意命令。

ExecuteStoreQuery<TElement>(String, Object[]) :對數據源直接執行查詢,此查詢將返回類型化結果的序列。

ExecuteStoreQuery<TEntity>(String, String, MergeOption, Object[]) :對數據源直接執行查詢,此查詢將返回類型化結果的序列。 指定實體集和合並選項,以便可以將查詢結果做爲實體進行跟蹤。

GetHashCode :用做特定類型的哈希函數。 (繼承自 Object。)

GetObjectByKey :返回具備指定實體鍵的對象。

公共方法 靜態成員 GetObjectType :返回與指定類型的代理對象關聯的 POCO 實體的實體類型。

LoadProperty(Object, String) :經過指定的導航屬性並使用默認合併選項,顯式加載與提供的對象相關的對象。

LoadProperty(Object, String, MergeOption) :經過指定的導航屬性並使用指定的合併選項,顯式加載與提供的對象相關的對象。

LoadProperty<TEntity>(TEntity, Expression<Func<TEntity, Object>>) :經過指定的 LINQ 查詢並使用默認合併選項,顯式加載與提供的對象相關的對象。

LoadProperty<TEntity>(TEntity, Expression<Func<TEntity, Object>>, MergeOption) :經過指定的 LINQ 查詢並使用指定的合併選項,顯式加載與提供的對象相關的對象。

Refresh(RefreshMode, IEnumerable) :使用數據源中的數據更新對象上下文中的對象集合。

Refresh(RefreshMode, Object) :使用數據源中的數據更新對象上下文中的對象。

SaveChanges() :將全部更新保存到數據源並重置對象上下文中的更改跟蹤。

SaveChanges(SaveOptions) :使用指定的 SaveOptions 將全部更新保存到數據源。

Translate<TElement>(DbDataReader) :將包含實體數據行的 DbDataReader 轉換爲請求的實體類型的對象。

Translate<TEntity>(DbDataReader, String, MergeOption) :在特定的實體集中,使用指定的合併選項將包含實體數據行的DbDataReader 轉換爲請求的實體類型的對象。

TryGetObjectByKey :返回具備指定實體鍵的對象。

 

屬性

CommandTimeout :獲取或設置全部對象上下文操做的超時值(以秒爲單位)。 null 值表示將使用基礎提供程序的默認值。

Connection :獲取對象上下文使用的鏈接。

ContextOptions :獲取 ObjectContextOptions 實例,該實例包含影響 ObjectContext 的行爲的選項。

DefaultContainerName :獲取或設置默認容器名稱。

MetadataWorkspace :獲取對象上下文使用的元數據工做區。

ObjectStateManager :獲取對象上下文用於跟蹤對象更改的對象狀態管理器。

 

事件

ObjectMaterialized :當使用數據源中的數據建立新的實體對象(做爲查詢或加載操做的一部分)時發生。

SavingChanges :在將更改保存到數據源時發生。

 

增長:AddObject

代碼片段:

using (var edm = new NorthwindEntities())

{

Customers c = new Customers { CustomerID = "notin",CompanyName="Astar"};

edm.AddObject("Customers", c);

int result = edm.SaveChanges();

 

Customers addc = edm.Customers.FirstOrDefault(cc => cc.CustomerID == "notin");

Console.WriteLine("CustomerId={0},CompanyName={1}", addc.CustomerID, addc.CompanyName);

}

 

主從添加:

using (var edm = new NorthwindEntities())

{

Categories categorie1 = new Categories { CategoryName = "ASP.NET" };

Categories categorie2 = new Categories { CategoryName = "SQLServer" };

Products product1 = new Products { ProductName = "ASP.NET 入門到精通", Discontinued = true };

Products product2 = new Products { ProductName = "SQLServer 入門到精通", Discontinued = false };

 

categorie1.Products.Add(product1);

categorie2.Products.Add(product2);

 

edm.Categories.AddObject(categorie1);

edm.Categories.AddObject(categorie2);

 

edm.SaveChanges();

 

Console.WriteLine("LinqToEntities...");

var categories = from categorie in edm.Categories

where categorie.CategoryName == "ASP.NET" || categorie.CategoryName == "SQLServer"

select categorie;

 

foreach (var categorie in categories)

{

Console.WriteLine("分類: {0}", categorie.CategoryName);

foreach (var product in categorie.Products)

{

Console.WriteLine("產品: {0}", product.ProductName);

}

}

 

Console.WriteLine("EntitySQL...");

//var esql = "select value c from Categories as c where exists(c.Products)"; //查詢所有

var esql = @"select value c from Categories as c where c.CategoryName = 'ASP.NET' or c.CategoryName = 'SQLServer'";

var categoriesESQL = edm.CreateQuery<Categories>(esql);

foreach (var categorie in categoriesESQL)

{

Console.WriteLine("分類: {0}", categorie.CategoryName);

foreach (var product in categorie.Products)

{

Console.WriteLine("產品: {0}", product.ProductName);

}

}

}

 

刪除:DeleteObject

代碼片段:

using (var edm = new NorthwindEntities())

{

Customers c = edm.Customers.FirstOrDefault(cc => cc.CustomerID == "notin");

edm.DeleteObject(c);

int result = edm.SaveChanges();

 

Customers addc = edm.Customers.FirstOrDefault(cc => cc.CustomerID == "notin");

//輸出異常,由於已爲NULL。

Console.WriteLine("CustomerId={0},CompanyName={1}", addc.CustomerID, addc.CompanyName);

}

 

修改:SaveChanges

代碼片段:

using (var edm = new NorthwindEntities())

{

Customers addc = edm.Customers.FirstOrDefault(cc => cc.CustomerID == "notin");

//addc.CustomerID = "notupdate"; //主鍵不可修改

addc.CompanyName = "Xlovey";

int result = edm.SaveChanges();

 

Customers updatec = edm.Customers.FirstOrDefault(cc => cc.CustomerID == "notin");

Console.WriteLine("CustomerId={0},CompanyName={1}", updatec.CustomerID, updatec.CompanyName);

}

 

結果:

 

執行SQL語句: ExecuteStoreCommand

代碼片段:

using (var edm = new NorthwindEntities())

{

string sqlStr = @"insert into Customers(CustomerID, CompanyName) values (@CustomerID, @CompanyName)";

var parm = new DbParameter[] {

new SqlParameter { ParameterName = "CustomerID", Value = "CR"},

new SqlParameter { ParameterName = "CompanyName", Value="Cnblogs"}

};

 

int rowCount = edm.ExecuteStoreCommand(sqlStr, parm);

 

Console.WriteLine("{0} rows inserted", rowCount.ToString());

 

Customers insertC = edm.Customers.FirstOrDefault(cc => cc.CustomerID == "CR");

Console.WriteLine("CustomerId={0},CompanyName={1}", insertC.CustomerID, insertC.CompanyName);

}

 

結果:

 

執行SQL語句並返回對象:ExecuteStoreQuery<TElement>

代碼片段:

string sqlStr = "select * from Customers where CompanyName = @CompanyName";

var parm = new DbParameter[] {

new SqlParameter {ParameterName = "CompanyName", Value = "Astar"}};

var customers = edm.ExecuteStoreQuery<Customers>(sqlStr, parm);

 

foreach (var customer in customers)

{

Console.WriteLine("{0},{1}",customer.CustomerID, customer.CompanyName);

}

 

ObjectStateEntry

維護對象或關係的 EntityStateEntityKey 值和原始值。還管理已修改屬性的列表。每一個實體類型關係實例都與一個ObjectStateEntry 實例關聯。 僅當對象在 ObjectStateManager 中時,才與 ObjectStateEntry 關聯。當具備關係的對象分離時,由 ObjectStateEntry 維護的信息會減小爲維護關係所需的信息。一個 ObjectStateEntry 不能有與同一 ObjectStateManager 中的另外一個 ObjectStateEntry 相同的鍵。

 

沒法修改持久性實體的鍵值。 處於更改、已修改和已刪除狀態的實體是持久性實體。

 

成員參考:http://msdn.microsoft.com/zh-cn/library/system.data.objects.objectstateentry_members.aspx

 

ObjectStateManager

ObjectStateManager 跟蹤查詢結果,並提供邏輯來合併多個重疊的查詢結果。 它還在用戶插入、刪除或修改對象時執行內存中的更改跟蹤,並提供用於更新的更改集。 更改處理器使用此變動集來持久保存修改。

 

此類一般由 ObjectContext 使用,不直接用於應用程序中。

 

成員參考:http://msdn.microsoft.com/zh-cn/library/system.data.objects.objectstatemanager_members.aspx

 

ObjectQuery

ObjectQuery 類支持對實體數據模型 (EDM) 執行 LINQ to Entities  Entity SQL 查詢。ObjectQuery 還實現了一組查詢生成器方法,這些方法可用於按順序構造等效於 Entity SQL 的查詢命令。每一個查詢生成器方法返回 ObjectQuery 的一個新實例。使用這些方法能夠構造查詢,而查詢的結果集基於前面 ObjectQuery 實例序列的操做。

 

經常使用方法和屬性

Execute():使用指定的合併選項執行非類型化對象查詢。

ToTraceString():返回要對數據源執行的命令。用於追蹤所執行的SQL語句,經過此方法咱們能夠獲取所執行的SQL語句,以便咱們查看、分析具體執行的SQL語句。

CommandText:返回查詢的命令文本。

 

Execute方法:返回ObjectResult

代碼片段:

using (var edm = new NorthwindEntities())

{

string sqlStr = "select value c from NorthwindEntities.Customers as c order by c.CustomerID limit 10";

 

ObjectQuery<Customers> query = edm.CreateQuery<Customers>(sqlStr);

ObjectResult<Customers> results = query.Execute(MergeOption.NoTracking);

foreach (Customers c in query)

{

Console.WriteLine(c.CustomerID);

}

}

 

MergeOption有四種值:

· AppendOnly 只追加新實體,不修改之前獲取的現有實體。這是默認行爲。

· OverwriteChanges  ObjectStateEntry 中的當前值替換爲存儲區中的值。這將使用服務器上的數據重寫在本地所作的更改。

· PreserveChanges 將替換原始值,而不修改當前值。這對於在發生開放式併發異常以後強制成功保存本地值很是有用。

· NoTracking 將不修改 ObjectStateManager,不會獲取與其餘對象相關聯的關係,能夠改善性能。

 

GetResultType方法:返回查詢結果的類型信息。

 

ToTraceString方法:獲取當前執行的SQL語句。

Console.WriteLine(query.ToTraceString());

 

Where方法

代碼片段:

string sqlStr = "select value c from NorthwindEntities.Customers as c order by c.CustomerID limit 10";

ObjectQuery<Customers> query = edm.CreateQuery<Customers>(sqlStr);

 

//使用ObjectParameter的寫法

query = query.Where("it.CustomerId=@customerid");

query.Parameters.Add(new ObjectParameter("customerid""ALFKI"));

 

//也能夠這樣寫

//ObjectQuery<Customers> query = edm.Customers.Where("it.CustomerID='ALFKI'");

 

foreach (var c in query)

{

Console.WriteLine(c.CustomerID);

}

 

First/ FirstOrDefault方法

代碼片段:

string sqlStr = "select value c from NorthwindEntities.Customers as c order by c.CustomerID limit 10";

 

ObjectQuery<Customers> query = edm.CreateQuery<Customers>(sqlStr);

 

//若是沒有符合條件的數據,那麼咱們的代碼將會拋出異常。

Customers c1 = query.First();

 

//若是沒有符合條件的數據,那麼它將返回null。

Customers c2 = query.FirstOrDefault();

 

Console.WriteLine(c1.CustomerID);

Console.WriteLine(c2.CustomerID);

 

Distinct方法:返回不重複的項。

代碼片段:

string sqlStr = "select value c.City from NorthwindEntities.Customers as c order by c.CustomerID limit 10";

 

ObjectQuery<string> query = edm.CreateQuery<string>(sqlStr);

query = query.Distinct();

foreach (string c in query)

{

Console.WriteLine("City {0}", c);

}

 

 

Except方法:返回兩個查詢的差集。

代碼片段:

string sqlStr = "select value c from NorthwindEntities.Customers as c order by c.CustomerID limit 10";

ObjectQuery<Customers> query1 = edm.CreateQuery<Customers>(sqlStr);

 

string sqlStr2 = "select value c from NorthwindEntities.Customers as c where c.Country='UK' order by c.CustomerID limit 10";

ObjectQuery<Customers> query2 = edm.CreateQuery<Customers>(sqlStr2);

 

query1 = query1.Except(query2);

foreach (Customers c in query1)

{

Console.WriteLine(c.Country);

}

 

Intersect方法:返回兩個查詢的交集。

代碼片段:

string sqlStr = "select value c from NorthwindEntities.Customers as c order by c.CustomerID limit 10";

ObjectQuery<Customers> query1 = edm.CreateQuery<Customers>(sqlStr);

 

string sqlStr1 = "select value c from NorthwindEntities.Customers as c where c.Country='UK' order by c.CustomerID limit 10";

ObjectQuery<Customers> query2 = edm.CreateQuery<Customers>(sqlStr1);

 

query1 = query1.Intersect(query2);

foreach (Customers c in query1)

{

Console.WriteLine(c.Country);

}

 

Union/UnionAll方法:返回兩個查詢的合集,包括重複項。其中UnionAll必須是相同類型或者是能夠相互轉換的。

 

Include方法:可經過此方法查詢出與相關的實體對象,至關於子查詢,能夠分析生成的SQL語句。

代碼片段:

string sqlStr = "select value c from NorthwindEntities.Customers as c WHERE c.CustomerID ='HANAR'";

 

ObjectQuery<Customers> query = edm.CreateQuery<Customers>(sqlStr);

query = query.Include("Orders");

foreach (Customers c in query)

{

Console.WriteLine("{0},{1}", c.CustomerID, c.Orders.Count);

}

 

Console.WriteLine(query.ToTraceString());

 

OrderBy方法

代碼片段:

string sqlStr = "select value c from NorthwindEntities.Customers as c order by c.CustomerID limit 10";

 

ObjectQuery<Customers> query = edm.CreateQuery<Customers>(sqlStr);

query.OrderBy("it.country asc,it.city asc");

 

//也能夠這樣寫

//query.OrderBy("it.country asc");

//query.OrderBy("it.city asc");

foreach (Customers c in query)

{

Console.WriteLine("{0},{1}", c.Country, c.City);

}

 

Select方法:只查詢須要的數據項。

代碼片段:

string sqlStr = "select value c from NorthwindEntities.Customers as c order by c.CustomerID limit 10";

 

ObjectQuery<Customers> query = edm.CreateQuery<Customers>(sqlStr);

ObjectQuery<DbDataRecord> records = query.Select("it.customerid,it.country");

 

foreach (DbDataRecord c in records)

{

Console.WriteLine("{0},{1}", c[0], c[1]);

}

 

Console.WriteLine(records.ToTraceString());

 

輸出結果:

ALFKI,Germany

ANATR,Mexico

ANTON,Mexico

AROUT,UK

BERGS,Sweden

BLAUS,Germany

BLONP,France

BOLID,Spain

BONAP,France

BOTTM,Canada

SELECT TOP (10)

1 AS [C1],

[Extent1].[CustomerID] AS [CustomerID],

[Extent1].[Country] AS [Country]

FROM [dbo].[Customers] AS [Extent1]

ORDER BY [Extent1].[CustomerID] ASC

 

SelectValue方法:查詢結果投影爲屬性。

代碼片段:

string sqlStr = "select value c from NorthwindEntities.Customers as c order by c.CustomerID limit 10";

 

ObjectQuery<Customers> query = edm.CreateQuery<Customers>(sqlStr);

ObjectQuery<string> records = query.SelectValue<string>("it.customerid");

foreach (string c in records)

{

Console.WriteLine("{0}", c);

}

 

Skip/Top方法:查詢分頁,核心利用SQLServer分頁函數。

代碼片段:

string sqlStr = "select value c from NorthwindEntities.Customers as c order by c.CustomerID ";

 

ObjectQuery<Customers> query = edm.CreateQuery<Customers>(sqlStr);

query = query.Skip("it.customerid asc""10");

query = query.Top("10");

foreach (Customers c in query)

{

Console.WriteLine("{0}", c.CustomerID);

}

 

Console.WriteLine(query.ToTraceString());

相關文章
相關標籤/搜索