zoukankan      html  css  js  c++  java
  • 实体框架中的POCO支持

    复杂类型(Complex Types)

      POCO中的复杂类型支持跟常规的基于EntityObject的实体中的复杂类型支持一样。你要做的就是将它们声明为POCO类,然后在你的POCO实体中使用和声明基于它们的属性。

      作为例子,这里是一个InventoryDetail复杂类型,代表我的Product实体的一个部分:

    1 public class InventoryDetail
    2 {
    3     public Int16 UnitsInStock { get; set; }
    4     public Int16 UnitsOnOrder { get; set; }
    5     public Int16 ReorderLevel { get; set; }
    6 } 

      把我的Product类修改成包含一个这个类型的属性,用来组合几个有关库存细节的字段:

     1 public class Product
     2 {
     3     public int ProductID { get; set; }
     4     public string ProductName { get; set; }
     5     public int SupplierID { get; set; }
     6     public string QuantityPerUnit { get; set; }
     7     public decimal UnitPrice { get; set; }
     8     public InventoryDetail InventoryDetail { get; set; }
     9     public bool Discontinued { get; set; }
    10     public Category Category { get; set; }
    11 }

      然后你可以做你以前对复杂类型所能做的一切,这是一个查询的例子:

    1 var outOfStockProducts = from c in context.Products
    2                          where c.InventoryDetail.UnitsInStock == 0
    3                          select c;

      你可以看到,POCO中的复杂类型支持用起来非常直截了当。但在POCO中使用复杂类型支持时,你需要记住几件事情:

    1. 你必须将复杂类型定义为类(class),结构体(struct)是不支持的。
    2. 在你的复杂类型类中,你不能使用继承。

      既然在讨论复杂类型,我想我要提一下另外一件事,你知道Visual Studio 2010中的实体框架设计器支持复杂类型的声明么?

      在Visual Studio 2008中,你只能手工将复杂类型的声明加到CSDL中去,但随着Visual Studio 2010中的设计器中对复杂类型支持的推出,这一切都成了历史。

      image

      更酷的是,因为Visual Studio 2010支持多定向(Multi-Targeting),你可以在开发针对.NET Framework 3.5,使用了Entity Framework 3.5的应用中也使用这个功能!

    延迟/懒式装载

      在我2个星期前发表的《延迟装载初览》一文中,我提到了实体框架现在支持延迟装载了。默认的、代码生成的基于EntityObject的实体类型将提供延迟装载,自然毫不奇怪。如果你想知道POCO对象中是否也支持延迟装载,那么我想,你会很高兴地知道,你在POCO中也能得到延迟装载支持。

      为在POCO实体中使用延迟装载支持,你需要做2件事情:

    1. 将你想要懒式装载的属性声明为virtual,这些属性可以是任何实现了ICollection<T> 的集合类,或者它们可以是代表了1/0..1 关系的引用。

      例如,这里是更新过的Category实体类的部分代码,我将其改成支持延迟装载了:

    1 public class Category
    2 {
    3     public int CategoryID { get; set; }
    4     public string CategoryName { get; set; }
    5     public string Description { get; set; }
    6     public byte[] Picture { get; set; }
    7     public virtual List<Product> Products { get; set; }
    8     ...

         2.   在上下文中启用延迟装载选项:

       1 context.ContextOptions.DeferredLoadingEnabled = true;  

      这就行了,你现在就将得到POCO类型的自动延迟装载,而不用做任何其他什么事情。

    那么这玩意到底是怎么工作的,底层是怎么进行的?

      这玩意能工作的原因是因为,在我将集合类型的属性标记为virtual后,这允许实体框架在运行时为我的POCO类型提供一个代理(proxy) 实例,正是这个代理实现了自动的延迟装载。该代理实例是基于一个继承自我的POCO实体类的类型,所以你提供的所有功能都被保留下来了。从开发人员的角度来看,即使延迟装载或许是个需求,这也允许你编写透明持久性的代码。

      如果你在调试器中检查实际的实例时,你会看到该实例的底层类型与我原先声明的类型是不同的:

      image

      虽然实体框架尽力以最小的摩擦提供自动的延迟装载,但在处理你想要添加或附加手工生成的实例时,或者当你序列化/发序列化实例时,这是你需要知道的事情。

    为POCO实体手工生成代理实例

      为了允许可以添加或附加的代理实例的生成,你可以使用ObjectContext上的CreateObject工厂方法来生成实体实例:

       1 Category category = context.CreateObject<Category>();  

      要把这个记住,在生成你想要用于实体框架的实例时,要使用CreateObject

    用“变动跟踪代理(Change Tracking Proxies)”来提供更有效的变动跟踪

      到目前为止,我们讨论过的标准POCO实体都依赖于基于快照(snapshot)的变动跟踪,即,实体框架会保管实体变动之前的值和关系的快照,这样,在保存(Save)时,可以与当前的值做比较。但这个比较的花销是相当大的,如果跟基于EntityObject的实体的变动跟踪的方式相比的话。

      还有另外一种类型的代理,它允许你在使用POCO实体时得到比较好的变动跟踪性能。

      如果你熟悉IPOCO接口,你知道IEntityWithChangeTracker是要求你在类中实现、来向实体框架提供变动通知的接口之一。

      变动跟踪代理从你的POCO实体类继承而来,在运行时给你提供这个功能,而不要求你自己实现IPOCO接口。

      从许多方面讲,用这种方式的话,你是鱼与熊掌都兼得了:你得到了POCO类的透明持久性,在变动跟踪方面你也得到了EntityObject / IPOCO 的性能。

      为了得到变动跟踪代理,基本的规则是,你的类必须是公开的,非抽象的或者非密封的(non-sealed)。你的类对所有要持久的属性都必须实现公开的virtual getters/setters。最后,你必须将基于集合的关系导航属性严格声明为ICollection<T>。它们不能是具体的实现或者继承自ICollection<T>的另外的接口(与延迟装载代理有所不同)。

      这里是我的Product POCO类的例子,它将在运行时给我提供更有效的基于代理的变动跟踪:

     1 public class Product
     2 {
     3     public virtual int ProductID { get; set; }
     4     public virtual string ProductName { get; set; }
     5     public virtual int SupplierID { get; set; }
     6     public virtual string QuantityPerUnit { get; set; }
     7     public virtual decimal UnitPrice { get; set; }
     8     public virtual InventoryDetail InventoryDetail { get; set; }
     9     public virtual bool Discontinued { get; set; }
    10     public virtual Category Category { get; set; }
    11 }

      再说一遍,要记住,如果你要将实体加到或附加到上下文的话,你必须使用CreateObject来生成代理实例。但不依赖代理的纯粹的POCO实体和基于代理的实体可以共处。你只有在涉及基于代理的实体时才需使用CreateObject。

    如果我想在同个POCO类型中同时启用延迟装载和更好的变动跟踪,该怎么办?

      这两个东西不是互相排斥的,你不必在延迟装载代理和变动跟踪代理间做选择。如果你想要延迟装载,以及有效的变动跟踪,你只要按照变动跟踪代理的规则办,以及启用延迟装载选项。变动跟踪代理会给你提供延迟装载,如果延迟装载选项是启用了的话。

    显式装载

      这个延迟装载的功能确实很棒,但你们中很多人大概想要完全控制你是如何装载相关实体的吧。你甚至会选择走纯粹的POCO之路,而不诉诸于任何自动代理生成能给你提供的功能。

      这是完全可以接受的,(在很多情形下也许是更好的方法),你可以使用显式关系装载,对你是如何在数据库中查询数据的做完全的控制。

      在POCO中做显式装载,有2个选项:

      一个是使用 ObjectContext.LoadProperty ,设置你想要装载的导航属性的名称:

       1 context.LoadProperty(beveragesCategory, "Products"); 

      这是可行的,但你可以看出来,这并不类型安全(type safe)。如果我没有正确的导航属性的名称的话,我会得到一个运行时异常。

      你们中的一些人大概更喜欢这个:

       1 context.LoadProperty(beveragesCategory, c => c.Products); 

      我可以使用lambda表达式来指定我想要显式装载的属性,这提供了更好的类型安全。

      上面是我计划在这第二个贴子里讨论的所有的内容了。但以后还会有更多内容,在这个系列的最后一篇里,我们将讨论在处理纯POCO(非代理化的)实例以及在你的对象图和对象状态管理器(Object State Manager)间保持一致时需要知道的几件事情。我们也会讨论你也许想要知道的SaveChanges方法的多个变种。

      与此同时,请看一下我更新过的样例代码,其中包括了我们在本贴里讨论过的一些东西。

      Faisal Mohamood  Entity Framework的Program Manager

  • 相关阅读:
    第二章 存储,2.1 永不停止的脚步——数据库优化之路(作者:佳毅)
    第一章 基础设施,1.3 阿里视频云ApsaraVideo是怎样让4000万人同时狂欢的(作者:蔡华)
    第一章 基础设施,1.2 双11背后基础设施软硬结合实践创新(作者:希有)
    第一章 基础设施,1.1 万亿交易量级下的秒级监控(作者:郁松、章邯、程超、癫行)
    阿里巴巴2016双11背后的技术(不一样的技术创新)
    java实现Haffman编码
    CentOS7安装Nginx并部署
    ubuntu usb权限问题解决
    Camera图像处理原理及实例分析-重要图像概念
    sensor的skipping and binning 模式
  • 原文地址:https://www.cnblogs.com/gamerLin/p/4452920.html
Copyright © 2011-2022 走看看