zoukankan      html  css  js  c++  java
  • 精进不休 .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 代码中不会有任何关于持久化的代码 
    • 其他新特性


    示例
    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>




    OK
    [源码下载]
  • 相关阅读:
    ThreadPoolHelper
    微软发布架构师期刊阅读器
    The Attribute basic
    静态构造函数(Static Constructor)(It performs well in Singleton)
    【代码保留】WebService发布本地磁盘信息
    oracle sqlplus
    【代码保留】IP地址排序(字符串分隔补齐)
    [WCF]How to Hosting?
    生成Xnb文件[转]
    sqlite 中文排序
  • 原文地址:https://www.cnblogs.com/webabcd/p/1759314.html
Copyright © 2011-2022 走看看