zoukankan      html  css  js  c++  java
  • 在 NHibernate 中一切必须是 Virtual 的吗?

    原文地址:Must Everything Be Virtual With NHibernate?

    老赵在博文中 我对NHibernate的感受(2):何必到处都virtual 提到这篇文章,顺便翻译一下。

    如果你使用过 NHibernate 2.0 或者以后的版本,毫无疑问你将会遇到过几次下面的异常:

    NHibernate.InvalidProxyTypeException: The following types may not be used as proxies:
    NHibernateExamples.Entities.OrderLine: method get_UnitPrice should be ‘public/protected virtual’ or ‘protected internal virtual’
    NHibernateExamples.Entities.OrderLine: method set_UnitPrice should be ‘public/protected virtual’ or ‘protected internal virtual’

    哎!我们忘了将 OrderList 实体的 UnitPrice 属性设置为 virtual 了。但是,为什么这里必须要设置为 virtual 呢?对于许多 NHibernate 的新手来说,这是一个问题。

    对于这个问题的简单答案是:将成员设置为 virtual 是为了延迟加载。

    更为详细的答案也更加有趣。 对于真正的 ORM 来说,必须具备的一个重要特征是透明的延迟加载。如果你通过 ORM 来获取一个对象,你不会希望它自动的将相关的整个对象图都拉过来(不包括默认情况),你也不会浪费你的代码来检查相关的对象是否已经加载了。应该在需要的时候加载它们,这是 ORM 的责任,理想情况下,如果这些数据还没有加载,在你第一次访问的时候,ORM 来加载需要的数据。

    NHibernate 具有这种能力,不需要你继承任何的 NHibernate 基类或者实现任何的接口,或者类似的任何东西。那么,它如何工作呢?好,NHibernate 在需要延迟加载的时候通过你的类的代理来完成。那么,什么是代理?在这里,NHibernate 的代理是一种在初始化应用程序的时候自动生成的类型(这仅仅发生在应用程序启动的时候),一种代理类型对应一种没有明确不使用延迟加载的实体类型,代理类型将会派生自你定义的实体类型,然后注入你可能在这种类型上的操作。

    让我们通过一个简单的例子来使这件事更加清楚一些,假设你定义了一个 Order 类,除了其他的成员之外,Order 类有像 Employee 和 Customer 的属性。当你加载 Order 实例的时候,你可能并不希望 Employee 属性已经包含了实际的 Employee 实体,类似地还有 Customer 属性,默认情况下,NHibernate 延迟加载每一个实体,除非明确配置为不延迟。所以,当 NHibernate 初始化的时候,它将会知道需要为 Employee 和 Customer 类型动态生成代理,假设相应的代理类型为 EmployeeProxyType 和 CustomerProxyType,实际的类型不是这些名称,但是不影响我们的讨论,现在,设想你获取了一个 Order 对象实例,你不希望 NHibernate 预先加载 Customer 和 Employee 数据,你没有请求 Customer 或者 Employee 数据,所以,现在还没有这些数据,对不对?但是他们也不应该是 null ,对吗?所以,NHibernate 赋予一个 CustomerProxyType 的实例给 Customer 属性,EmployeeProxyType 的实例给 Employee 属性,然后,初始化这两个属性,使其包含标识信息,这样,你就得到了内存中的订单数据。

    你可以安全的使用 Order 实例,甚至可以访问 Employee 和 Customer 属性,但是,一旦你访问没有实际数据的代理成员,包括属性和方法,NHibernate 需要确信 Customer 或者 Employee 的数据从数据库已经获取,NHibernate 怎么处理呢?代理将会重写所有你的属性和方法,当其中任何一个被访问的时候,如果数据还没有实际获取,NHibernate 将会加载数据,然后执行原来属性或者方法的实现逻辑,如果数据已经获取,那么,就会直接调用原来的实现逻辑。

    这是基本的面向对象,你定义的实体对于 NHibernate 代理来说是一个基类,这些代理需要扩展你定义实体的行为,来完成上述的功能,NHibernate 需要 override 任何的公共成员来确信在适当的时间触发这些行为。现在,有不少的人不喜欢这种要求。首先,认为这是一个主要的性能花费,访问虚拟成员要比访问非虚拟成员费时,然而,这种性能损失非常小,几乎在任何情况下都可以完全忽略不计。这种花费与真正的性能花费完全不能相比,比如数据库访问的花费。另外一个不喜欢的原因是他们不希望派生类 override 他们的任何成员,在某些情况下,这是一个有力的理由,但是,实际上没有价值。有其他的 ORM 实现不需要你的成员是 virtual 的情况下仍然可以延迟加载,但是,这些 ORM 实现经常要求你或者派生自某个特定的基类,或者实现一个或者多个 ORM 使用的接口,在这两种情况下,我认为 NHibernate 的做法对实体的影响远远低于其他的 ORM ,不过,这只是我的意见。

    但是,如果你真的不需要成员是 virtual,而且不使用 NHibernate 的延迟加载,你只需要简单地映射你的实体不使用延迟加载即可,你的映射文件应该如下所示:

     <class name="OrderLine" table="OrderLine" lazy="false" >

    将 lazy 属性设置为 false 将会确信 NHibernate 不会创建你的实例类型的代理类型,你将会得到实际定义的实体类型对象实例,而不会是代理类型的对象实例,这也代表在获得实体对象的时候你将不会得到任何类型的延迟加载。

  • 相关阅读:
    Azure PowerShell (2) 修改Azure订阅名称
    Windows Azure Platform Introduction (11) 了解Org ID、Windows Azure订阅、账户
    Azure PowerShell (3) 上传证书
    Azure PowerShell (1) PowerShell入门
    Windows Azure Service Bus (2) 队列(Queue)入门
    Windows Azure Service Bus (1) 基础
    Windows Azure Cloud Service (10) Role的生命周期
    Windows Azure Cloud Service (36) 在Azure Cloud Service配置SSL证书
    Android studio 使用心得(一)—android studio快速掌握快捷键
    android 签名、混淆打包
  • 原文地址:https://www.cnblogs.com/haogj/p/1930494.html
Copyright © 2011-2022 走看看