为什么Nhibernate中属性和方法必须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'
哎呀,我们忘记把OrderLine实体中的UnitPrice属性标志成virtual的了,奇怪的是,为什么它一开始的时候必须要设置成virtual的,这是一个对于初次接触NHibernate的人经常有的疑惑。
针对这个问题,最简洁的答案就是:因为我们需要把成员设置成virtual的,是为了实现我们的延迟加载的魔幻功能。
但是更详细点的答案反而更有趣,我们知道任何真正的ORM必须要有的一个重要功能就是延迟加载,如果你通过ORM获取一个对象,你不会希望它去自动的获取整个对象图中所有数据(默认情况下应当不是), 还有你也不希望添加一些凌乱的代码去检查特定的关联关系是否已经被加载了,我们需要的是只有我们的需要的时候才去加载它们。这应该是ORM的职责。理想情况下应该是,你能访问这些属性,而且如果这时数据还没有加载,当你第一次访问的时候,ORM会负责加载当前需要的数据。
NHiernate 拥有这项能力,但是它却不要求你继承NHibernate中的某项基类或者实现一些接口。那奇怪了
? Nhibernate是怎么做到的呢?其实,当需要延迟加载时,在运行期,Nhibernate用的是你的类的代理(proxy)。 那代理又是什么呢? 一个Nhibernate代理指的是当你的程序初始化Nhibernate的时候(发生在应用程序第一次启动的时候,并且只发生一次),Nhibernate动态生成的一个类型。如果你没有显示的给你的Entity指定不需要延迟加载,那Nhibernate会为你的每一个Entity生成一个代理,每一个Entity代理的类型其实是继承与这个Entity的。这样你在操作这个类型的时候,你就可以做一些拦截操作。
为了使这个过程变得更清晰,我们举个小例子。假设你有一个Order类,这个Order类有一些属性如Employee,Customer和其它。 但是当你加载Order实体的时候,你也许不想让Employee属性已经包含了真正的Employee实例。对于Cutomer属性也是同样的。默认情况下,Nhibernate认为每个实体类型都是要延迟加载的,除非你显示的告诉它不用延迟加载。所以,当Nhibernate一开始初始化的时候,它会知道它需要动态的为Customer和Employee生成代理(proxy)类型。在这我们假设两个类型的名字为CustomerProxyType和EmployeeProxyType (在现实中它们不会叫这个名字,但是这个不重要). 现在假设你去获取Order实例,这时你还没有去请求Customer或者Employee的数据,所以它们应当是不存在的,对吧? 但是它们也不为Null, 因为Nhibernate 为Customer属性分配了CustomerProxyType的实例,为Employee属性分配了EmployeeProxyType实例。并且还为每一个实例初始化了它们的标识符的值,一般是ID的值。这个标识符的值是在查询order记录的时候获取到的。
你现在可以放心的使用Order实例,你甚至可以访问Employee和Customer的实例,这时什么也不会发生,不会有查询操作。但是,注意,当你去访问代理实例的非标识符成员(也就是属性和方法)的时候,Nhibernate为了确保你请求的非标识符成员有数据,它会去数据库请求数据。在这里就是当你去访问Employee和Customer的属性和方法的时候,Nhibernate会去数据库请求你想要的数据。那Nhibernate是怎么实现的这种机制呢? 因为代理会重写你的实体类(Entity)的属性和方法,当属性和方法被调到的时候,Nhibernate会检查,如果当前实例的数据已经存在了,它就只会调用实体类(Entity)中属性和方法的实现,如果没有数据,它会先去获取数据,然后再调用实体类(Entity)中属性和方法的实现。
这是基本的面相对象思想,你的实体类(Entity)是Nhibernate 代理的基类。 这些代理(proxy)会为你的实体类(Entity)的行为上添加一些额外的行为。 Nhibernate需要重写所有的公共成员(public)来确保在合适的时间这些额外的行为能被触发。
为什么Nhibernate中属性和方法必须Virtual的的更多相关文章
- js中属性和方法的类型和区别
对象的属性:私有属性(var).类属性(静态属性).对象属性(this).原型属性(prototype). 对象的方法: 私有方法(funtion).类方法(静态方法).对象方法(this).原型方法 ...
- Java继承中属性、方法和对象的关系
大家都知道子类继承父类是类型的继承,包括属性和方法!如果子类和父类中的方法签名相同就叫覆盖!如果子类和父类的属性相同,父类就会隐藏自己的属性! 但是如果我用父类和子类所创建的引用指向子类所创建的对象, ...
- python中类中属性和方法的具体定义方法和使用
1. Python中类中特性分成属性和方法 属性和方法都分为私有和公有的,私有的只可以在本类中使用外部是无法访问的 2. 定义属性(成员变量)的语法格式(公有属性/私有属性) class 类名: de ...
- OC中属性及方法
1.声明式属性 a.实例变量 b.声明属性 自动生成setter/getter方法 .h ->@property 属性类型 属性名; .m ...
- php中属性和方法的修饰符
<?php class A{ private function do1(){ echo "do1 called"; } protected function do2(){ e ...
- Python中类的方法属性与方法属性的动态绑定
最近在学习python,纯粹是自己的兴趣爱好,然而并没有系统地看python编程书籍,觉得上面描述过于繁琐,在网站找了一些学习的网站,发现廖雪峰老师的网站上面的学习资源很不错,而且言简意赅,提取了一些 ...
- Java 类、属性、方法修饰符 public、private、protected、default
Java 中修饰类修饰符:public .default (默认) Java 中修饰类中属性.方法修饰符:public.private.protected.default (默认) 通过 IDEA 创 ...
- java利用反射访问类的私有(private)属性及方法
Java语言中,在一个类中,为了不让外界访问到有的属性和方法,通常将其设置为private,用正常的方式(对象名.属性名,对象名.方法名)将无法访问此属性与方法,但有没有其他方法可以访问呢?答案是有的 ...
- 在 NHibernate 中一切必须是 Virtual 的吗?
原文地址:Must Everything Be Virtual With NHibernate? 老赵在博文中 我对NHibernate的感受(2):何必到处都virtual 提到这篇文章,顺便翻译一 ...
随机推荐
- JDBC操作数据库 封装好的工具类
mysql sqlserver oracle 数据库的驱动jar包http://download.csdn.net/download/csdn576038874/8833683package cn.h ...
- Silverlight OOB 程序自动更新
Silverlight OOB 程序 提供了非常方便的自动更新功能! 要让 Silverlight OOB 安装到客户端电脑后实现自动更新,必须实现以下两个条件: 一.为 程序的 xap 文件进行签 ...
- System Operations on AWS - Lab 5W - Managing Resources (Windows)
登陆到CommandHost实例,通过AWS CLI来管理各个资源 1. 通过Tags来管理资源 1.1 登陆到CommandHost实例 1.2 找出development实例 1.2.1 打开Po ...
- Linux删除文件Argument list too long问题的解决方案
方法一:使用find find . -name 文件 | xargs rm -f 但文件数量过多,find命令也会出现问题: -bash: /bin/find: Argument list too l ...
- 2015前端各大框架比较(angular,vue,react,ant)
前端流行框架大比拼 angular vue react ant-design angularjs angular是个MVVM的框架.针对的是MVVM这整个事.angular的最主要的场景就是单页应用, ...
- c语言训练题:关于张三李四王五说谎的问题(此处用javascript实现)
(第一篇博文) 今天在一个交流群里见他们无聊,然后找到之前收藏的一些c语言题目放出去想让他们做,结果反倒是自己不会做,于是花了很多时间去想. 原题:张三说李四在说谎,李四说王五在说谎,王五说张三和李四 ...
- 造一个Badge Service(徽章)的轮子
什么是Badge Service 细心的读者朋友一定在很多Github的Repo,npm的package页面看到过诸如 的徽章.这些徽章是干什么用的? 大家看到上文中我引用的Badge的左侧,是Dow ...
- css - div垂直方向滚动
只要设置 OVERFLOW-Y:auto;OVERFLOW-X:hidden即可.
- SET NOCOUNT 的意义.
SET NOCOUNT 使返回的结果中不包含有关受 Transact-SQL 语句影响的行数的信息. 语法 SET NOCOUNT { ON | OFF } 当 SET NOCOUNT 为 ON 时, ...
- sqlserver2005唯一性约束
[转载]http://blog.163.com/rihui_7/blog/static/21228514320136193392749/ 1.设置字段为主键就是一种唯一性约束的方法,如 int p ...