[索引頁]
[×××]
精進不休 .NET 4.0 (7) - ADO.NET Entity Framework 4.0 新特性
做者:
webabcd
介紹
ADO.NET Entity Framework 4.0 的新增功能
- 對外鍵的支持,即把外鍵當作實體的一個屬性來處理
- 對複雜類型的支持,即實體屬性能夠是一個複雜類型
- 將多個表映射到一個概念實體,將一個表拆爲多個概念實體
- 加強了 LINQ to Entities
- 新增了對 POCO(Plain Old CLR Object)的支持,即 Model 代碼中不會有任何關於持久化的代碼
- 其餘新特性
示例
一、外鍵 的 Demo
EntityFramework/ForeignKeys/Demo.aspx.cs
/*
* ADO.NET Entity Framework 4.0 - 新增了對外鍵的支持,即把外鍵當作實體的一個屬性來處理
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace DataAccess.EntityFramework.ForeignKeys
{
public partial
class Demo : System.Web.UI.Page
{
Random _random =
new Random() Random _random =
new Random();
void Page_Load() void Page_Load(object sender, EventArgs e)
{
// 在一個已存在的產品類別下新建一個產品(經過外鍵值)
using (var ctx =
new ForeignKeysEntities())
{
Product p =
new Product
{
Name =
"webabcd test" + _random.
Next().ToString(),
ProductNumber = _random.
Next().ToString(),
StandardCost = 1,
ListPrice = 1,
SellStartDate = DateTime.Now,
rowguid = Guid.NewGuid(),
ModifiedDate = DateTime.Now,
ProductCategoryID = 18
};
// 這裏須要手工 Add 這個新的 Product,而後再調用 SaveChanges()
ctx.Products.AddObject(p);
Response.Write(ctx.SaveChanges());
}
Response.Write(
"<br /><br />");
// 在一個已存在的產品類別下新建一個產品(經過外鍵對象)
using (var ctx =
new ForeignKeysEntities())
{
Product p =
new Product
{
Name =
"webabcd test" + _random.
Next().ToString(),
ProductNumber = _random.
Next().ToString(),
StandardCost = 1,
ListPrice = 1,
SellStartDate = DateTime.Now,
rowguid = Guid.NewGuid(),
ModifiedDate = DateTime.Now,
ProductCategory = ctx.ProductCategories.Single(c => c.ProductCategoryID == 18)
};
// 這裏直接調用 SaveChanges() 便可,而不用再手工地 Add 這個新的 Product
// 由於與這個新的 Product 關聯的那個已存在的 ProductCategory 會自動地 Add 這個新的 Product
Response.Write(ctx.SaveChanges());
}
}
}
}
二、複雜類型的 Demo
EntityFramework/ComplexType/Demo.aspx.cs
/*
* ADO.NET Entity Framework 4.0 - 新增了對複雜類型的支持,即實體屬性能夠是一個複雜類型
* 一、在 EDM 設計器中的實體上,點擊右鍵,在「Add」選項中能夠新建一個複雜類型
* 二、在 EDM 設計器中的實體上,選中多個屬性後,點擊右鍵,選擇「Refactor into
New Complex Type」能夠合併多個屬性爲一個複雜類型
* 三、在 EDM 設計器中的「Mapping Details」窗口或「Model Broswer」窗口裏,能夠對複雜類型作編輯
*
* ADO.NET Entity Framework 4.0 - 對存儲過程的支持有了明顯的加強
* 表現爲:能夠將存儲過程的返回值映射到一個自定義的複雜類型上,固然,這個複雜類型也能夠根據儲過程的返回值自動生成
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace DataAccess.EntityFramework.ComplexType
{
public partial
class Demo : System.Web.UI.Page
{
void Page_Load() void Page_Load(object sender, EventArgs e)
{
using (var ctx =
new ComplexTypeEntities())
{
// 這裏的 Name 類型是自定義的一個複雜類型(其有三個屬性,分別爲FirstName, MiddleName, LastName),詳見 EDM
Name name = ctx.Customers.First().Name;
Response.Write(
string.Format(
"FirstName: {0}<br />MiddleName: {1}<br />LastName: {2}", name.FirstName, name.MiddleName, name.LastName));
}
Response.Write(
"<br /><br />");
using (var ctx =
new ComplexTypeEntities())
{
// 這裏的 MyCustomer 類型,是存儲過程 uspSelectCustomer(其概念模型爲:GetCustomer()) 的返回值的映射類型
MyCustomer customer = ctx.GetCustomer().First();
Response.Write(
string.Format(
"CustomerID: {0}<br />FirstName: {1}<br />MiddleName: {2}<br />LastName: {3}", customer.CustomerID, customer.FirstName, customer.MiddleName, customer.LastName));
}
}
}
}
三、將一個表拆爲多個概念實體的 Demo
EntityFramework/TableSplitting/Demo.aspx.cs
/*
一、將多個表映射到一個概念實體,原來就能夠。在 EDM 設計器中將兩個一對一的表映射到一個實體便可
二、將一個表拆爲多個概念實體,原來也行,可是要在 xml 中手工配置。如今 VS2010 中只需在 EDM 設計器中作以下設置:
a、新建兩個實體,作好相關字段相對於原表的映射
b、在這兩個實體間新建一個一對一的關聯
c、雙擊這個關聯線,編輯約束,指明主表和依賴表,並設置相關的主鍵
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace DataAccess.EntityFramework.TableSplitting
{
public partial
class Demo : System.Web.UI.Page
{
void Page_Load() void Page_Load(object sender, EventArgs e)
{
// 將一個 ErrorLog 表映射到兩個實體上 ErrorLog 和 ErrorLogExt,詳見 EDM
using (var ctx =
new TableSplittingEntities())
{
ErrorLog log = ctx.ErrorLogs.First();
Response.Write(log.ErrorLogID);
Response.Write(
"<br />");
log.ErrorLogExtReference.Load();
Response.Write(log.ErrorLogExt.ErrorMessage);
}
}
}
}
四、LINQ to Entities 新功能的 Demo
EntityFramework/LINQ2Entities/Demo.aspx.cs
/*
* ADO.NET Entity Framework 4.0 - 加強了 LINQ
to Entities
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Data.Objects;
using System.Data.Common;
namespace DataAccess.EntityFramework.LINQ2Entities
{
public partial
class Demo : System.Web.UI.Page
{
void Page_Load() void Page_Load(object sender, EventArgs e)
{
Demo1();
Demo2();
// 支持 Single() 擴展方法了,以前的版本不支持
}
void Demo1() void Demo1()
{
// ADO.NET Entity Framework 4.0 - 新增了 System.Data.Objects.EntityFunctions 和 System.Data.Objects.SqlClient.SqlFunctions
// 其做用至關於 Linq
to Sql 中的 System.Data.Linq.SqlClient.SqlMethods
using (var ctx =
new LINQ2EntitiesEntities())
{
var products =
from p
in ctx.Products
where System.Data.Objects.SqlClient.SqlFunctions.DateDiff(
"year", p.SellStartDate, DateTime.Now) <= 10
select p;
Response.Write((products
as System.Data.Objects.ObjectQuery).ToTraceString());
Response.Write(
"<br />");
Response.Write(
"十年內銷售的產品數量爲:" + products.Count());
}
Response.Write(
"<br /><br />");
// 上面的示例若是寫成 esql 就是以下的寫法。固然這個原來就支持。
using (var ctx =
new LINQ2EntitiesEntities())
{
string esql =
"select value p from LINQ2EntitiesEntities.Products as p where SqlServer.DATEDIFF('year', p.SellStartDate, SqlServer.GETDATE()) <= 10";
//
string esql =
"using SqlServer; select value p from LINQ2EntitiesEntities.Products as p where DATEDIFF('year', p.SellStartDate, GETDATE()) <= 10";
ObjectQuery<Product> products = ctx.CreateQuery<Product>(esql);
Response.Write(products.ToTraceString());
Response.Write(
"<br />");
Response.Write(
"十年內銷售的產品數量爲:" + products.Count());
}
Response.Write(
"<br /><br />");
}
void Demo2() void Demo2()
{
// 使用 esql 的方式調用 sql 中的用戶自定義函數
using (var ctx =
new LINQ2EntitiesEntities())
{
string esql =
"select value top(1) LINQ2EntitiesModel.Store.ufnGetFullName(c.firstName, c.middleName, c.lastName) from LINQ2EntitiesEntities.Customers as c";
ObjectQuery<
string> customers = ctx.CreateQuery<
string>(esql);
Response.Write((customers
as System.Data.Objects.ObjectQuery).ToTraceString());
Response.Write(
"<br />");
foreach (var customerName
in customers.ToList())
{
Response.Write(customerName);
Response.Write(
"<br />");
}
}
Response.Write(
"<br /><br />");
// clr 的方式調用 sql 的用戶自定義函數。具體實現見 MyClass 類
using (var ctx =
new LINQ2EntitiesEntities())
{
var customers =
from c
in ctx.Customers
select MyClass.GetFullName(c.FirstName, c.MiddleName, c.LastName);
customers = customers.Take(1);
Response.Write((customers
as System.Data.Objects.ObjectQuery).ToTraceString());
Response.Write(
"<br />");
foreach (var customerName
in customers.ToList())
{
Response.Write(customerName);
Response.Write(
"<br />");
}
}
}
public static
class MyClass
{
// System.Data.Objects.DataClasses.EdmFunction(
string namespaceName,
string functionName) - 將 sql 中的指定的用戶自定義函數映射到 clr 的方法上
//
string namespaceName - SSDL(存儲模型)的命名空間,能夠在 edmx 文件中找到這個值
//
string functionName - sql 中的用戶自定義函數名
[System.Data.Objects.DataClasses.EdmFunction(
"LINQ2EntitiesModel.Store",
"ufnGetFullName")]
/// <summary>
/// 此方法的參數要與其所映射的 sql 用戶自定義函數的參數相匹配
/// 此方法只可用於 linq 表達式,方法內不用作任何實現
/// </summary>
static
string GetFullName() static
string GetFullName(
string firstName,
string middleName,
string lastName)
{
throw
new NotSupportedException(
"You can only call this method as part of a LINQ expression");
}
}
}
}
五、POCO 的 Demo
Demo.aspx
<%@ Page Language=
"C#" AutoEventWireup=
"true" CodeBehind=
"Demo.aspx.cs"
Inherits=
"POCODemo.Demo" %>
<!DOCTYPE html
PUBLIC
"-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns=
"http://www.w3.org/1999/xhtml">
<head runat=
"server">
<title></title>
</head>
<body>
<form id=
"form1" runat=
"server">
<div>
ADO.NET Entity Framework 4.0 - 新增了對 POCO(Plain Old CLR Object)的支持,即 Model 代碼中不會有任何關於持久化的代碼
<ul>
<li>一、線上有 POCO 的 T4(Text Template Transformation Toolkit)模板</li>
<li>二、在 EDM 設計器上單擊右鍵,選擇「Add Code Generation Item」,在線上模板中選擇「ADO.NET C# POCO Entity Generator」模板生成便可</li>
<li>三、在 EF 中,POCO 與非 POCO 不能在一個項目中共存,由於非 POCO 的 EF 在 assembly 級別上會有以下聲明<br />
using System.Data.Objects.DataClasses;<br />
[assembly: EdmSchemaAttribute()]<br />
而 POCO 不須要這個聲明,因此一個程序集內不能既有 POCO 又有非 POCO </li>
<li>四、具體的 POCO 代碼,詳見本例中的由 POCO 模板生成的代碼 </li>
</ul>
</div>
</form>
</body>
</html>
六、其餘新特性
EntityFramework/Others.aspx
<%@ Page Title=
"其它,一筆帶過" Language=
"C#" MasterPageFile=
"~/Site.Master" AutoEventWireup=
"true"
CodeBehind=
"Others.aspx.cs"
Inherits=
"DataAccess.EntityFramework.Others" %>
<asp:Content ID=
"Content1" ContentPlaceHolderID=
"head" runat=
"server">
</asp:Content>
<asp:Content ID=
"Content2" ContentPlaceHolderID=
"ContentPlaceHolder1" runat=
"server">
<p>
一、T4 模板引擎(微軟的一個代碼生成引擎) - Text Template Transformation Toolkit
</p>
<p>
二、加強了 EDM 設計器
</p>
<p>
三、對 Model-First 的支持,即根據概念模型生成存儲模型和映射模型
<ul>
<li>在概念模型(EDM 設計器)上單擊右鍵,選擇「 Generate Database from Model」,便可生成數據庫腳本</li>
<li>
在 EDM 設計器中,與 Model-First 相關的字段屬性說明
<ul>
<li>StoreGeneratedPattern - 該字段所對應的數據庫中的列屬性(有三種:無,自增,經過計算而來)</li>
<li>FixedLength - FixedLength=
true 對應 nchar, FixedLength=
false 對應 nvarchar</li>
<li>Unicode - 是不是 Unicode 編碼。好比字符串若是是非 Unicode 則對應 varchar,若是是 Unicode 則對應 nvarchar</li>
<li>Max Length - 最大字符數。對應 varchar(n) 或 nvarchar(n) 中的 n</li>
</ul>
</li>
</ul>
</p>
<p>
四、Code Only - 在 POCO 的基礎上,連 EDM 也不須要了(即不用再作概念模型,映射模型,存儲模型的配置), 純寫代碼便可,惋惜在 EF 4.0 的正式版裏這個功能被去掉了
</p>
<p>
五、 改進了 SQL 語句的生成
</p>
<p>
六、Lazy Loading - 支持延遲加載,相關設置 context.ContextOptions.DeferredLoadingEnabled =
true; 其默認值就是
true
</p>
<p>
七、
Explicit Loading - 顯示加載,看下面的例子
<ul>
<li>加載導航屬性的方法以下(固然 Include 也能夠達到一樣的效果)context.LoadProperty(category,
"Products");</li>
<li>上面那個方法(包括 Include)不太好,由於若是實體集名稱寫錯的話 runtime 的時候是才能發現,因此爲了不寫錯可使用以下方法 context.LoadProperty(category, c => c.Products);</li>
</ul>
</p>
<p>
八、幾種自帶的 T4 模板的說明
<ul>
<li>ADO.NET EntityObject Generator - 把 edmx 文件中的內聯代碼摘出來</li>
<li>ADO.NET POCO Entity Generator - 生成 POCO(Plain Old CLR Object) 實體,其包括每一個表所映射的實體及一個Context,POCO 中不會包含持久化相關的代碼(這個模板非內置,能夠在線上模板中找到)</li>
<li>ADO.NET Self-Tracking Entity Generator - POCO 的增強版,在 POCO 的基礎上增長了實體狀態自跟蹤的功能</li>
</ul>
</p>
<p>
九、新建 EDM 的時候,在嚮導中有一個選項「pluralize
or singularize generated object names」,其意思爲:生成對應的 Model 時,實體名稱自動用單數形式,實體集名稱自動用複數形式
</p>
</asp:Content>