zoukankan      html  css  js  c++  java
  • 【转】【翻译】实体框架中的POCO支持 第二部分 复杂类型,延迟装载和显式装载

    【原文地址】POCO in the Entity Framework : Part 2 – Complex Types, Deferred Loading and Explicit Loading
    【原文发表日期】 28 May 09 09:03 AM

    在上星期的贴子《POCO Experience in Entity Framework》 (实体框架中的POCO体验)中,我讨论了Entity Framework 4.0中POCO支持的基本。在这个贴子里,我将讨论与POCO相关的另外几个方面。

    复杂类型(Complex Types)

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

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

    public class InventoryDetail
    {
    public Int16 UnitsInStock { get; set; }
    public Int16 UnitsOnOrder { get; set; }
    public Int16 ReorderLevel { get; set; }
    }

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

    public class Product
    {
    public int ProductID { get; set; }
    public string ProductName { get; set; }
    public int SupplierID { get; set; }
    public string QuantityPerUnit { get; set; }
    public decimal UnitPrice { get; set; }
    public InventoryDetail InventoryDetail { get; set; }
    public bool Discontinued { get; set; }
    public Category Category { get; set; }
    }

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

    var outOfStockProducts = from c in context.Products
    where c.InventoryDetail.UnitsInStock == 0
    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实体类的部分代码,我将其改成支持延迟装载了:

    public class Category
    {
    public int CategoryID { get; set; }
    public string CategoryName { get; set; }
    public string Description { get; set; }
    public byte[] Picture { get; set; }
    public virtual List<Product> Products { get; set; }
    ...

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

    context.ContextOptions.DeferredLoadingEnabled = true;

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

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

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

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

    image

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

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

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

    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类的例子,它将在运行时给我提供更有效的基于代理的变动跟踪:

    public class Product
    {
    public virtual int ProductID { get; set; }
    public virtual string ProductName { get; set; }
    public virtual int SupplierID { get; set; }
    public virtual string QuantityPerUnit { get; set; }
    public virtual decimal UnitPrice { get; set; }
    public virtual InventoryDetail InventoryDetail { get; set; }
    public virtual bool Discontinued { get; set; }
    public virtual Category Category { get; set; }
    }

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

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

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

    显式装载

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

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

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

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

    context.LoadProperty(beveragesCategory, "Products");

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

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

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

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

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

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

    Faisal Mohamood
    Entity Framework的Program Manager



    推荐文章
  • 相关阅读:
    (转)批量导出存储过程
    (转)ylbtech-cnblogs(博客园)-数据库设计-6.0-Msg(短消息)
    (转)怎样玩转千万级别的数据
    (转)处理上百万条的数据库如何提高处理查询速度
    (转)SQLSERVER表分区的介绍(二)
    (转)SQLSERVER表分区的介绍(一)
    (转)在SQL中取出字符串中数字部分或在SQL中取出字符部分
    (转)SQL按照日、周、月、年统计数据
    构建操作mysql的类
    解决Celery 在Windows中搭建和使用的版本
  • 原文地址:https://www.cnblogs.com/fcsh820/p/1866348.html
Copyright © 2011-2022 走看看