原文地址: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. 用Fiddler可以设置浏览器的UA 和 手动 --Chrome模拟手机浏览器(iOS/Android)的三种方法,亲测无误!

    附加以一种软件的方法是:用Fiddler可以设置浏览器的UA 以下3种方法是手动的 通过伪装User-Agent,将浏览器模拟成Android设备. 第一种方法:新建Chrome快捷方式 右击桌面上的 ...

  2. Effective STL读书笔记

    Effective STL 读书笔记 本篇文字用于总结在阅读<Effective STL>时的笔记心得,只记录书上描写的,但自己尚未熟练掌握的知识点,不记录通用.常识类的知识点. STL按 ...

  3. 安卓开发笔记——Broadcast广播机制(实现自定义小闹钟)

    什么是广播机制? 简单点来说,是一种广泛运用在程序之间的传输信息的一种方式.比如,手机电量不足10%,此时系统会发出一个通知,这就是运用到了广播机制. 广播机制的三要素: Android广播机制包含三 ...

  4. UNIX环境编程学习笔记(24)——信号处理进阶学习之信号集和进程信号屏蔽字

    lienhua342014-11-03 1 信号传递过程 信号源为目标进程产生了一个信号,然后由内核来决定是否要将该信号传递给目标进程.从信号产生到传递给目标进程的流程图如图 1 所示, 图 1: 信 ...

  5. [转]jmeter 自定义测试脚本

    http://blog.csdn.net/kash_chen007/article/details/37690411 http://wangym.iteye.com/blog/731729 1.创建一 ...

  6. MongoDB 之 Capped Collection

    MongoDB 支持 Capped Collection,一种固定大小的集合,当集合的大小达到指定大小时,新数据覆盖老数据,MongoDB Replica set 中的 oplog 就是 Capped ...

  7. 深入解析Java AtomicInteger原子类型

    深入解析Java AtomicInteger原子类型 在并发编程中,需要确保当多个线程同时访问时,程序能够获得正确的结果,即实现线程安全.线程安全性定义如下: 当多个线程访问一个类时,无论如何调度运行 ...

  8. django 配置中STATICFILES_DIRS 和STATIC_ROOT不能同时出现

    系统环境: win7 django版本查看: 启动django项目的时候,一直找不到静态资源,很奇怪放在linux服务器上的时候好好的,拿下来随便修改了配置就说url找不到了. 用wingIDE没有任 ...

  9. 用FileExplorer查看android手机中的数据库

    想查看一下手机中的通讯录数据库,google之后找到了办法. 参考: http://stackoverflow.com/questions/4867379/android-eclipse-ddms-c ...

  10. windows下WAMP php5.x redis扩展

    其解压到php的扩展目录ext下,在php.ini文件中扩展部分增加一行:extension=php_redis.dll 新增下载地下: php5.3 http://download.csdn.net ...