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

  • 相关阅读:
    DPDK安装方法 17.12.13
    numa.h:No such file or directory 解决方法
    17秋 软件工程 第六次作业 Beta冲刺 Scrum3
    17秋 软件工程 第六次作业 Beta冲刺 总结博客
    17秋 软件工程 第六次作业 Beta冲刺 Scrum2
    Paper Reviews and Presentations
    17秋 软件工程 第六次作业 Beta冲刺 Scrum1
    17秋 软件工程 第六次作业 Beta冲刺
    error: could not create '/System/Library/Frameworks/Python.framework/Versions/2.7/share': Operation not permitted
    17秋 软件工程 个人作业 软件产品案例分析
  • 原文地址:https://www.cnblogs.com/gamerLin/p/4452920.html
Copyright © 2011-2022 走看看