介紹
ADO.NET Entity Framework 4.0 的新增功能
* 對外鍵的支持,即把外鍵當做實體的一個屬性來處理
* 對復雜類型的支持,即實體屬性可以是一個復雜類型
* 將多個表映射到一個概念實體,將一個表拆為多個概念實體
* 增強了 LINQ to Entities
* 新增了對 POCO(Plain Old CLR Object)的支持,即 Model 代碼中不會有任何關於持久化的代碼
* 其他新特性
示例
1、外鍵 的 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
{
private Random _random = new Random();
protected 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());
}
}
}
}
2、復雜類型的 Demo
EntityFramework/ComplexType/Demo.aspx.cs
代碼
/*
* ADO.NET Entity Framework 4.0 - 新增了對復雜類型的支持,即實體屬性可以是一個復雜類型
* 1、在 EDM 設計器中的實體上,點擊右鍵,在“Add”選項中可以新建一個復雜類型
* 2、在 EDM 設計器中的實體上,選中多個屬性後,點擊右鍵,選擇“Refactor into New Complex Type”可以合並多個屬 性為一個復雜類型
* 3、在 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
{
protected 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));
}
}
}
}
3、將一個表拆為多個概念實體的 Demo
EntityFramework/TableSplitting/Demo.aspx.cs
代碼
/*
1、將多個表映射到一個概念實體,原來就可以。在 EDM 設計器中將兩個一對一的表映射到一個實體即可
2、將一個表拆為多個概念實體,原來也行,但是要在 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
{
protected 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);
}
}
}
}
4、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
{
protected void Page_Load(object sender, EventArgs e)
{
Demo1();
Demo2();
// 支持 Single() 擴展方法了,之前的版本不支持
}
private 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 />");
}
private 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>
public static string GetFullName(string firstName, string middleName, string lastName)
{
throw new NotSupportedException("You can only call this method as part of a LINQ expression");
}
}
}
}
5、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>1、線上有 POCO 的 T4(Text Template Transformation Toolkit)模板</li>
<li>2、在 EDM 設計器上單擊右鍵,選擇“Add Code Generation Item”,在線上模板中選擇“ADO.NET C# POCO Entity Generator”模板生成即可</li>
<li>3、在 EF 中,POCO 與非 POCO 不能在一個項目中共存,因為非 POCO 的 EF 在 assembly 級別上會有如下聲明 <br />
using System.Data.Objects.DataClasses;<br />
[assembly: EdmSchemaAttribute()]<br />
而 POCO 不需要這個聲明,所以一個程序集內不能既有 POCO 又有非 POCO </li>
<li>4、具體的 POCO 代碼,詳見本例中的由 POCO 模板生成的代碼 </li>
</ul>
</div>
</form>
</body>
</html>
6、其他新特性
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>
1、T4 模板引擎(微軟的一個代碼生成引擎) - Text Template Transformation Toolkit
</p>
<p>
2、增強了 EDM 設計器
</p>
<p>
3、對 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>
4、Code Only - 在 POCO 的基礎上,連 EDM 也不需要了(即不用再做概念模型,映射模型,存儲模型的配 置), 純寫代碼即可,可惜在 EF 4.0 的正式版裡這個功能被去掉了
</p>
<p>
5、 改進了 SQL 語句的生成
</p>
<p>
6、Lazy Loading - 支持延遲加載,相關設置 context.ContextOptions.DeferredLoadingEnabled = true; 其默認值就是 true
</p>
<p>
7、Explicit Loading - 顯示加載,看下面的例子
<ul>
<li>加載導航屬性的方法如下(當然 Include 也可以達到同樣的效果)context.LoadProperty(category, "Products");</li>
<li>上面那個方法(包括 Include)不太好,因為如果實體集名稱寫錯的話 runtime 的時候是才能發現,所以為了避免寫錯可 以使用如下方法 context.LoadProperty(category, c => c.Products);</li>
</ul>
</p>
<p>
8、幾種自帶的 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>
9、新建 EDM 的時候,在向導中有一個選項“pluralize or singularize generated object names”,其意 思為:生成對應的 Model 時,實體名稱自動用單數形式,實體集名稱自動用復數形式
</p>
</asp:Content>