原文地址: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 不会创建你的实例类型的代理类型,你将会得到实际定义的实体类型对象实例,而不会是代理类型的对象实例,这也代表在获得实体对象的时候你将不会得到任何类型的延迟加载。

在 NHibernate 中一切必须是 Virtual 的吗?的更多相关文章

  1. 为什么Nhibernate中属性和方法必须Virtual的

    如果你曾经用过NHibernate 2.0或者更高的版本,那您一定碰到过下面的错误:NHibernate.InvalidProxyTypeException: The following types ...

  2. NHibernate 中使用 nvarchar(max) 类型

    在 NHibernate 中使用字符串类型,默认会映射到字符类型,在 SQLServer 中,NVARCHAR 类型最大长度是 4000 字符,如果超过 4000,比如使用 SQL Server 中的 ...

  3. [转]NHibernate之旅(7):初探NHibernate中的并发控制

    本节内容 什么是并发控制? 悲观并发控制(Pessimistic Concurrency) 乐观并发控制(Optimistic Concurrency) NHibernate支持乐观并发控制 实例分析 ...

  4. NHibernate之旅(7):初探NHibernate中的并发控制

    本节内容 什么是并发控制? 悲观并发控制(Pessimistic Concurrency) 乐观并发控制(Optimistic Concurrency) NHibernate支持乐观并发控制 实例分析 ...

  5. NHibernate之旅(14):探索NHibernate中使用视图

    本节内容 引入 1.持久化类 2.映射文件 3.測试 结语 引入 在数据库操作中,我们除了对表操作,还有视图.存储过程等操作,这一篇和下篇来学习这些内容.这篇我们来学习怎样在NHibernate中使用 ...

  6. NHibernate中,查询SqlServer数据库多个实体对象

    关于datetime类型使用:  Oracle:  "and tb.EffectiveDate >= to_date(?,'yyyy-mm')" Sql:  "an ...

  7. NHibernate 中删除数据的几种方法

    今天下午有人在QQ群上问在NHibernate上如何根据条件删除多条数据,于是我自己就写了些测试代码,并总结了一下NHibernate中删除数据的方式,做个备忘.不过不能保证囊括所有的方式,如果还有别 ...

  8. Nhibernate中 Many-To-One 中lazy="proxy" 延迟不起作用的原因

    2010-07-15 12:10 by 彭白洋, 322 阅读, 0 评论, 收藏, 编辑 NHibernate中 Many-To-One 中lazy="proxy" 延迟不起作用 ...

  9. [转]NHibernate之旅(6):探索NHibernate中的事务

    本节内容 事务概述 1.新建对象 [测试成功提交] [测试失败回滚] 2.删除对象 3.更新对象 4.保存更新对象 结语 上一篇我们介绍了NHibernate中的Insert, Update, Del ...

随机推荐

  1. 关于Struts2的文件上传

    要实现Struts2框架的文件上传,需要用到2个jar包 commons-fileupload-1.2.2.jar commons-io-2.0.1.jar 由于文件解析Struts2内部已经帮我们做 ...

  2. jquery获取data-xxx自定义属性的值遇到的问题

    直接用jquery的 data("name") 获取 data-name的值有问题,获取的只是最初的值,即使后边改变也不会变,所以还是要用attr("data-name& ...

  3. 续:纠正:ubuntu 【6.04 LTS】可以安装安装 ! for《Oracle-10.2.0.1,打补丁10.2.0.5:在 debian 版本4【不含4】以上,及 ubuntu 7.04【不含7.04】以上都可以安装!》

    经过长时间的试错.探索,终于查明无法顺利安装oracle10g的原因,并且找到顺利安装的方式. 要点: 无法安装的根本原因有2: 1:libc6-dev的版本为2.23-0ubuntu10,其中的cr ...

  4. 使用psutil库监控linux的系统资源和自定义进程的cpu 内存占用。

    #coding=utf8 import time import psutil from pprint import pprint from logger_until import LoggerUnti ...

  5. SpringMVC由浅入深day01_2springmvc入门程序

    2 入门程序 2.1 需求 以案例作为驱动. springmvc和mybaits使用一个案例(商品订单管理). 功能需求:商品列表查询 2.2 环境准备 数据库环境:mysql5.5 先导入sql_t ...

  6. [转]如何配置和使用Tomcat访问日志

    配置位置在log下的server.xml,(tomcat容器) <Engine defaultHost="localhost" name="Catalina&quo ...

  7. 使用 vux 框架

    1)vux官网:https://vux.li/#/ 2)通过 vue-cli 工具使用 vux 1.如果没有安装 nodejs,请先前往 nodejs 官网下载并安装 nodejs,传送门:https ...

  8. c++的字节对齐

    win32平台下的微软C编译器对齐策略: 1)结构体变量的首地址能够被其最宽数据类型成员的大小整除.编译器在为结构体变量开辟空间时,首先找到结构体中最宽的数据类型,然后寻找内存地址能被该数据类型大小整 ...

  9. Ubuntu 13.10 下安装搜狗输入法

    1.卸载ibus输入法: sudo apt-get remove ibus     sudo为取得root权限的意思,Ubuntu系统默认root账户关闭,很多操作需要取得root     权限才可以 ...

  10. The content of the adapter has changed but ListView did not receive a notification. Make sure the content of your adapter is not modified from a background thread, but only from the UI thread. Make s

    我出现这个问题是引用资源文件问题 helper.getView(R.id.in_pic).setBackgroundResource(item.getResourceId()); //错的helper ...