精進不休 .NET 4.0 (7) - ADO.NET Entity Framework 4.0 新特性

[索引頁]
[×××]


精進不休 .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>
 
 
相關文章
相關標籤/搜索