上一篇主要是在夸NHibernate实现的好,而这篇就完全是来抱怨的了。NHiberante有个毛病,就是如果是和数据库产生映射的类,就要求所有的public成员和protected成员必须是virtual的。请注意这里的要求有两个细节:

  • 即使是方法,也必须标记为virtual
  • 即时是不和数据库有映射关系的属性,也必须标记为virtual

这就让我觉得无厘头了,为什么没有任何关系的东西也要受到限制?我知道NHiberante要求将属性标记为virtual是为了延迟加载,因为只有这样它才能生成如上一篇文章中那样的延迟代理类,这样就可以实现只在第一次访问属性的时候才进行“加载”操作,从而访问数据库并获得数据,再填充字段。不过我认为这也不是合适的理由,因为这又关没有映射的属性,甚至方法什么事情呢?我在很长一段时间内一直没有想明白这个问题。

直到看了NHibernate开发团队成员Davy Brion的文章《Must Everything be Virtual with NHiberante?》之后,我才了解了他们的设计思路——虽然我还是不认同。我真的不喜欢到处virtual

要求类中所有的公开成员(public/protected)都是virtual,是因为NHibernate想要保证在“访问任何公开成员”之前,数据已经被加载了。也就是说,无论您是想调用它的ToString方法,还是您自己写的辅助方法/属性,在真正进入您自定义的逻辑之前,数据肯定已经存在了——例如,存在于私有的域字段中:

public class Article
{
private string m_tagNames
public virtual string TagNames
{
get
{
return this.m_tagName;
}
set
{
this.m_tagNames = value;
}
} public void DoSomethingWithTagNames()
{
Console.WriteLine(this.m_tagNames);
}
}

虽然NHibernate可以在TagNames属性第一次访问时加载数据,但是如果我们的DoSomethingWithTagNames方法直接访问m_tagNames字段,数据自然无法加载了。因此,NHibernate必须确保有能力在代理类中覆盖DoSomethingWithTagNames方法才行。这就是virtual方法的由来。

但是在我看来,我们真的有多少情况会去访问私有字段呢?事实上对于大部分情况,我们会使用C#中“自动属性”特性来定义属性,这样自然只有属性,没有字段。即使我们使用了自定义的私有字段来保存属性的值,NHibernate也可以“叮嘱”我们应该访问属性,而不要直接访问私有字段——其实在编程上两者并没有差别。现在这样被强迫的感觉不好。

不过昨天我忽然想到,这似乎也是可以理解NHibernate这么做的原因:因为Hibernate要照顾到Java语言开发人员的使用感受——请注意是Hibernate,没有N。不管怎么说,NHibernate是从Hibernate移植过来的。NHiberante的主力开发人员Oren Eini曾在博客中写道(可惜一时没找到),NHiberante刻意与Hibernate的实现保持同步,这样容易进行双向的同步,例如Hibernate解决了一些bug或性能问题,也可以较为轻易地在NHibernate上修补。

不过这还是没有解释为什么Hibernate要一切都是virutal的原因啊。其实您只要看一下这段Java代码就应该明白了:

public class Product
{
private String m_tagNames; public String getTagNames()
{
return this.m_tagNames;
} public String setTagNames(String value)
{
this.m_tagNames = value;
}
}

这是上面C#中Product的等价Java代码。由于Java里没有“属性”概念,因此Java语言自身一直有一个“约定”:getXxx和setXxx两个方法即为一个属性。这个约定用在很多地方,如IDE就会把它当作是一个属性方便设置及导航,框架在进行序列化时候也知道哪些东西是“属性”。这“约定”本没有问题,但是这就给Java开发人员造成了一定困扰:使用起来实在是太麻烦了。例如,Product有个属性叫做ViewCount,我们想要把它加1,在C#中我们可以写:

this.ViewCount++;

而在Java中则必须是:

this.setViewCount(this.getViewCount() + 1);

因此,如果是你的话,在写Java代码的时候,是愿意使用getXxx()这样的方法,还是直接访问类中的私有字段?因此我认为,是Java语言的特性,导致Java开发人员倾向于直接访问类中的私有字段,从而导致Hibernate需要避免未加载的私有字段,进一步导致Hibernate的代理类会去覆盖所有的公开方法(只有方法,因为Java语言没有“属性”)——最终,由于NHibernate在“统一大业”上的策略,使得我们.NET开发人员也必须把所有成员标记为virtual,无论是方法还是属性。

您可能会说,但也没见Java程序员嚷嚷啊。没错,因为在Java语言中,默认情况下所有的成员都是virtual的。而在.NET平台下情况正好相反。因此在我看来,我们这里必须到处标记virtual所造成的不便,和Java语言本身有着非常大联系——我们需承受Java语言所带来的痛苦。

虽然我理解NHibernate,但这又怎能让我满意呢?

哦,对了。在未来的Java 7中,我们可歌可泣的Java语言终于有了a –> property这样的属性访问语法了。

可惜,迟了。

转自:http://blog.zhaojie.me/2009/09/my-view-of-nhibernate-2-virtually-everything.html

我对NHibernate的感受(2):何必到处都virtual的更多相关文章

  1. 我对NHibernate的感受(4):令人欣喜的Interceptor机制

    之前谈了NHibernate的几个方面,似乎抱怨的居多,不过这次我想谈一下我对Interceptor的感受,则基本上都是好话了.这并不一定是说Interceptor设计的又多么好(事实上它使用起来还是 ...

  2. 到处都是坑的微信支付V3之 微信支付回调页面

    据上次 到处都是坑的微信支付V3 后很多园友在被虐了千百遍后终于跳转到了亲切的微信支付界面,但输入密码支付后却不知道怎么处理了,接下来补上支付后的处理流程. 1. html中根据前台支付后反馈信息成功 ...

  3. 到处都是坑的微信支付V3

    业务需要一个在微信上能付款的功能,于是乎想到了最普遍的支付宝,坑爹的是T与A是水火不容啊,默默的还是接微信支付吧,没想到从此掉进了连环坑…… 网上写微信支付接口的还是很多,PHP官方有(鄙视源码作者, ...

  4. 我对NHibernate的感受(3):有些尴尬的集合支持

    既然是一个ORM框架,那么自然是将O这一端映射R上.至于集合,是O这方面最常见,也是R这一边非常容易表示的关系.例如,一个问题(Question)可以包含多个回答(Answer),于是我的代码里就有这 ...

  5. 我对NHibernate的感受(1):对延迟加载方式的误解

    NHibernate是.NET平台上最著名的ORM框架,虽说出身于Java平台上的Hibernate,但是从外部看来这几乎就是一个.NET平台上的原生产品:有自己的社区,有自己的用户,有自己的商业支持 ...

  6. 不是什么时候都可以用栈来声明对象并使用(自动释放)——Delphi里到处都是编译器魔法,并且自动帮助实例化界面元素指针

    一直都喜欢这样显示窗口,因为简单高效: void MainWidget::ShowMyWindow() { MyWidget form(this); form.resize(,); form.exec ...

  7. Java教程到处都是,究竟怎样能学好Java?

    学习Java如何入门?学习教程要点是什么?如何精通?做好以下这些点,入门更快,掌握Java更轻松. Java必备基础知识 1.你需要精通面向对象分析与设计(OOA/OOD).涉及模式(GOF,J2EE ...

  8. 这是100年后火星的未来,到处都是CBD!

    ​火星是个荒漠之地,尽管如此,最近几十年人类一直准备登录火星,然后殖民火星.随着科技的迅猛发展,感觉火星离我们越来越近了.不过,人类如何在火星上生存下去,这一直是科学家们最热衷的话题. ​意大利建筑师 ...

  9. 在 NHibernate 中一切必须是 Virtual 的吗?

    原文地址:Must Everything Be Virtual With NHibernate? 老赵在博文中 我对NHibernate的感受(2):何必到处都virtual 提到这篇文章,顺便翻译一 ...

随机推荐

  1. Java 中 日期 时间 加减

    DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); //方法1(推荐,功能强大灵活多变) Ca ...

  2. python图片处理(一)

    在matlab中有相应的图像进行二值化处理,并且标记连通区域 L = bwlabel(BW,n) 返回一个和BW大小相同的L矩阵,包含了标记连BW中每个连通区域的类别标签,标签的值是1.2.num(连 ...

  3. Unix IPC之FIFO

    #include "unpipc.h" #define FIFO1 "/tmp/fifo.1" #define FIFO2 "/tmp/fifo.2& ...

  4. Failed to create the Java Virtual Machine

    启动Zend Studio时出现Failed to create the Java VIrtual Machine 解决办法如下.打开安装目录下的ZendStudio.ini配置文件,作如下修改: 说 ...

  5. LoadRunner11-遇到问题及解决办法(汇总)

    LoadRunner11-遇到问题及解决办法 1.LoadRunner超时错误:在录制Web服务器端,如果超过120秒服务器协议脚本回放时超时情况经常出现,产生错误的原因也有很多,解决的方法也不同.错 ...

  6. JSP的学习二(请求转发与 重定向)

    一: 1.介绍知识点 1). 本质区别: 请求的转发只发出了一次请求, 而重定向则发出了两次请求. 具体: ①. 请求的转发: 地址栏是初次发出请求的地址.  请求的重定向: 地址栏不再是初次发出的请 ...

  7. html5+css3 手机屏幕的适配css

    *{ margin:0;padding:0;outline:0}a{ text-decoration:none}body,html{ font-size:20px;font-family:'Micro ...

  8. The file will have its original line endings in your working directory.

    在空仓库的情况下,add,出现一下问题 The file will have its original line endings in your working directory. 当报这个警告时是 ...

  9. CSUOJ 1726 你经历过绝望吗?两次!BFS+优先队列

    Description 4月16日,日本熊本地区强震后,受灾严重的阿苏市一养猪场倒塌,幸运的是,猪圈里很多头猪依然坚强存活.当地15名消防员耗时一天解救围困的"猪坚强".不过与在废 ...

  10. HDU 6103 Kirinriki (思维 双指针)

    Kirinriki Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total S ...