Hello World
Spiga

我对NHibernate的感受(2):何必到处都virtual

2009-09-24 15:09 by 老赵, 16432 visits

上一篇文章主要是在夸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这样的属性访问语法了。

可惜,迟了。

相关文章

Creative Commons License

本文基于署名 2.5 中国大陆许可协议发布,欢迎转载,演绎或用于商业目的,但是必须保留本文的署名赵劼(包含链接),具体操作方式可参考此处。如您有任何疑问或者授权方面的协商,请给我留言

Add your comment

68 条回复

  1. 五味果
    *.*.*.*
    链接

    五味果 2009-09-24 15:15:00

    沙发?
    难得!

  2. 五味果
    *.*.*.*
    链接

    五味果 2009-09-24 15:16:00

    终于坐了一次偶像的沙发!
    无论是体重还是技术,或者减肥...

  3. 李永京
    *.*.*.*
    链接

    李永京 2009-09-24 15:18:00

    这篇知道了....

  4. rockshit
    *.*.*.*
    链接

    rockshit 2009-09-24 15:23:00

    java 中 string类型的 == 和equals也是会产生困惑的。

  5. Tristan G
    *.*.*.*
    链接

    Tristan G 2009-09-24 15:32:00

    这么看来,是NHiberate的开发人员太体贴了。为了避免用户使用Property不当,强行把所有成员的访问都拦截了...

  6. 淘者天下2
    *.*.*.*
    链接

    淘者天下2 2009-09-24 15:36:00

    NHibernate可以用于大型项目吗,具体如何配置呀!

  7. 老赵
    admin
    链接

    老赵 2009-09-24 15:37:00

    @Tristan G
    是,但是我不喜欢这种强制……

  8. 老赵
    admin
    链接

    老赵 2009-09-24 15:37:00

    @淘者天下2
    本就是为了应付大型项目才搞得如此复杂的。
    具体如何配置看文档。

  9. craboYang
    *.*.*.*
    链接

    craboYang 2009-09-24 15:41:00

    我这辈子没去做Java,就是因为Java的属性居然是getXXX,setXXX, 被他给厌烦死了的。

  10. 老赵
    admin
    链接

    老赵 2009-09-24 15:43:00

    @Ryan Gene
    对,就是这个意思。
    如果要延迟加载的属性,virtual是必须的。
    但是NH要求所有的公开方法都要virtual,这我不愿意啊。
    我只要访问的时候从属性下手就行了,把我掐那么死做什么……

  11. 李永京
    *.*.*.*
    链接

    李永京 2009-09-24 15:43:00

    @Ryan Gene

  12. Ryan Gene
    *.*.*.*
    链接

    Ryan Gene 2009-09-24 15:46:00

    Jeffrey Zhao:
    @Ryan Gene
    对,就是这个意思。
    如果要延迟加载的属性,virtual是必须的。
    但是NH要求所有的公开方法都要virtual,这我不愿意啊。
    我只要访问的时候从属性下手就行了,把我掐那么死做什么……



    可能老赵是ddd的关系吧?会在entity里加些方法什么的,我的话用工具生成这些entity,所以一般不会在entity里写其他方法。

  13. Ryan Gene
    *.*.*.*
    链接

    Ryan Gene 2009-09-24 15:48:00

    后来想想所有公开方法要求virtual是有点强制,property强制到是应该的,所以把先前的评论删了~

  14. YJJ
    *.*.*.*
    链接

    YJJ 2009-09-24 15:52:00

    老赵对首页发起总攻........

  15. 问问123[未注册用户]
    *.*.*.*
    链接

    问问123[未注册用户] 2009-09-24 15:55:00

    最近在学设计模式,看老赵的推荐书籍里有王翔写的那本设计模式,老赵有什么推荐原因吗?

  16. 菌哥
    *.*.*.*
    链接

    菌哥 2009-09-24 15:56:00

    一直关注NH,一直关注老赵对NH的理解

  17. 钢钢
    *.*.*.*
    链接

    钢钢 2009-09-24 16:00:00


    最近在玩JAVA,所以对你这篇文章看得很有滋味。

    @rockshit
    没弄错的话:
    java 中 string类型的 == 是比较内存地址
    而 string类型的 equals 和C#一样,都是重写了,比较值本身。

  18. 老赵
    admin
    链接

    老赵 2009-09-24 16:06:00

    @问问123
    写的好呗……不多对于初学者来说,不一定合适,那本书工程意味重啊。

  19. LeoXing
    *.*.*.*
    链接

    LeoXing 2009-09-24 16:17:00

    这个比第一篇好理解多了,NHibernate这么做确实有点强制的把java的思想灌溉到.net当中的意味。

  20. Yok
    *.*.*.*
    链接

    Yok 2009-09-24 16:17:00

    如果不默认使用lazy load,就不需要virtual了

  21. LeoXing
    *.*.*.*
    链接

    LeoXing 2009-09-24 16:20:00

    @Yok
    这么好的设计,为什么会不用呢?

  22. 小赛布里
    *.*.*.*
    链接

    小赛布里 2009-09-24 17:02:00

    Jeffrey Zhao:
    事实上对于大部分情况,我们会使用C#中“自动属性”特性来定义属性,这样自然只有属性,没有字段。



    试问如果需要在属性块里检查长度或者添加其他逻辑,如何使用“自动属性”实现呢?

  23. RednaxelaFX
    *.*.*.*
    链接

    RednaxelaFX 2009-09-24 17:08:00

    等等……Project Coin里没有接纳property syntax诶,JDK 7是难得看到a->prop = b;的写法了 =v=

  24. 老赵
    admin
    链接

    老赵 2009-09-24 17:08:00

    @小赛布里
    那肯定就无法用自动属性了。

  25. Vincent Zhou
    *.*.*.*
    链接

    Vincent Zhou 2009-09-24 17:36:00

    哎 为啥我用nhibernate这么久,就没深思过这个问题呢
    向高手学习!!!

  26. Ivony...
    *.*.*.*
    链接

    Ivony... 2009-09-24 18:21:00

    呵呵,我就知道吧。。。。。

    NHibernate说到底还是Java框架的移植品。它所追求的所谓ORM,即对象-关系映射其实是一个不切实际的理想,这与Java的风格不无关系。即使戴上了N的帽子,它也不是.NET哲学下的东西。

    话说.NET下应该不乏比NHibernate更好用的框架,只是没有NHibernate看起来那么“恢宏”罢了,这也是所有Java移植品的通性。但恢宏不代表一切。

  27. 老赵
    admin
    链接

    老赵 2009-09-24 18:27:00

    @Ivony...
    但现在NHibernate有什么替代品呢?

  28. 尘尘
    *.*.*.*
    链接

    尘尘 2009-09-24 21:03:00

    话说
    老赵写博客用的是什么?
    排版很不错的

  29. riccc
    *.*.*.*
    链接

    riccc 2009-09-25 04:45:00

    记得没错的话禁用延迟加载就不必用virtual了,全局禁用可以将use_proxy_validator配置为false,某个类禁用可以将他的lazy配置为false,这一点可以验证一下,我手头没有nhibernate环境

    代理方面应当是用Castle的DynamicProxy实现透明代理,要求方法为virtual的确是受限于DynamicProxy的实现机制,但原因仅此而已,跟private field没有任何关系

    field, property是历来沿用的设计原则,在rich model中如果getter, setter中有业务,其他成员方法改用field是很正常的现象,设想如果hibernate不能正确处理他们的加载问题,反而是一个设计缺陷,使用field还是getXxx()方法跟贪图方便是没有联系的。nhibernate的access method也支持property, field等,nhibernate的源代码中也有很多区别的对待property和field进行处理的地方,例如使用Emit代替反射提高实体的创建速度等都需要考虑access method,所有这些仅仅是因为一个使用习惯问题怎么能够说的过去

  30. heros
    *.*.*.*
    链接

    heros 2009-09-25 08:53:00

    virtual的才可以被override,这是C#的严格的地方。一直认为C#的严格性要强于java,甚至类库的实现也一样,就比如hashtable,在java中key值重复添加时竟然是覆盖原来的value。跑题了。
    nhibernate这么的做法虽然有一棒子打死的嫌疑,但正如楼主文中讲的一样,谁又能保证程序员不去直接操作私有成员,nhibernate的virtual到底的做法也可理解。

  31. Ivony...
    *.*.*.*
    链接

    Ivony... 2009-09-25 09:21:00

    Jeffrey Zhao:
    @Ivony...
    但现在NHibernate有什么替代品呢?




    我想,这个问题应该改成,NHibernate到底有什么不可替代的东西。


    Java的项目有时候总是会追求体系完备性,或许这与Java本身的Framework不完备有关系。但这些项目却又是由顶尖的程序员联合完成的,对于这些程序员而言,设计的艺术性有时候可能比完备性更为重要。在艺术性和完备性不能兼得的时候,会发现Java的项目总是力图保证艺术气质却又不愿丢弃体系完备。就像Java很难得出现WebForm控件模型一样,因为ASP.NET最初版本的年代,技术条件和思想都不足以很有艺术性的在Web上创建完备的控件模型。

    ASP.NET的WebForm在框架上的确是不美的,我们能看到很多难受的设计。想必当初做这些东西的程序员心里也一定是很难受的吧。但正由于这种不美,这种难受,才使得我们能提前在Web上享受完备的控件模型。

    所以这就是.NET和Java的项目在风格上的不同,.NET的开源项目没有Java的心理包袱,不太追求体系完备,只要能解决一个小问题,也就足够。因为恢宏的框架有微软来完成,不美的东西可以提交给微软去做。而Java的项目却总是希望成为一个万年基业,各方面都十分完备,但在这样的思想驱动下,这些程序员却不得不面对体系完备和设计艺术的冲突。结果最后总是能形成各种看起来很美的框架。。。。

  32. JimLiu
    *.*.*.*
    链接

    JimLiu 2009-09-25 09:26:00

    Jeffrey Zhao:
    因此我认为,是Java语言的特性,导致Java开发人员倾向于直接访问类中的私有字段,从而导致Hibernate需要避免未加载的私有字段,进一步导致Hibernate的代理类会去覆盖所有的公开方法


    是啊是啊。。。别说Java了,C++就是这样,JAVA为了更好地“传承”C++,这么做了,但是语言中设计一个Property实在是太方便程序员了,JAVA现在认识到这一点,但是真的晚了点。我想真正在用Java7的程序员也有大多数不会去用这个obj->property,因为思维定势嘛。

    小赛布里:
    试问如果需要在属性块里检查长度或者添加其他逻辑,如何使用“自动属性”实现呢?


    对贫血模型我采取彻底贫血的做法,既是不在实体类属性逻辑中判断任何属性的约束,而是在旁边引入一组Validator来完成这个事情。所以我没有你这个烦恼,可以完全用自动属性。

  33. Ivony...
    *.*.*.*
    链接

    Ivony... 2009-09-25 09:32:00

    JimLiu:

    Jeffrey Zhao:
    因此我认为,是Java语言的特性,导致Java开发人员倾向于直接访问类中的私有字段,从而导致Hibernate需要避免未加载的私有字段,进一步导致Hibernate的代理类会去覆盖所有的公开方法


    是啊是啊。。。别说Java了,C++就是这样,JAVA为了更好地“传承”C++,这么做了,但是语言中设计一个Property实在是太方便程序员了,JAVA现在认识到这一点,但是真的晚了点。我想真正在用Java7的程序员也有大多数不会去用这个obj->property,因为思维定势嘛。

    小赛布里:
    试问如果需要在属性块里检查长度或者添加其他逻辑,如何使用“自动属性”实现呢?


    对贫血模型我采取彻底贫血的做法,既是不在实体类属性逻辑中判断任何属性的约束,而是在旁边引入一组Validator来完成这个事情。所以我没有你这个烦恼,可以完全用自动属性。




    Java沿用C++的思想,能用现有语法解决的问题,就不是语法的问题,哪怕语法多难看。但C++可以用宏和运算符重载替换掉难看的语法,Java却没有。

    另外对“贫血”这个伪发明的滥用发表一点儿个人抗议。

  34. JimLiu
    *.*.*.*
    链接

    JimLiu 2009-09-25 09:47:00

    @Ivony...
    说到运算符重载,Java不支持运算符重载这一点也让我很惊讶(不是不满),因为我觉得从编译器角度这个功能是不难实现的,从语言特性来说这是独立的不会干涉别的语言特性,但是Java就是不支持,表面上看这减少了一些语言的复杂度,但是去带来了一些麻烦事情,就好比.equals和==。孰优孰劣,很难说。
    贫血的“滥用”,我不敢说我没有,因为我并不擅长设计,我很多时候只会自作聪明地发明一些有点怪异的方法。

  35. Ivony...
    *.*.*.*
    链接

    Ivony... 2009-09-25 09:52:00

    JimLiu:
    @Ivony...
    说到运算符重载,Java不支持运算符重载这一点也让我很惊讶(不是不满),因为我觉得从编译器角度这个功能是不难实现的,从语言特性来说这是独立的不会干涉别的语言特性,但是Java就是不支持,表面上看这减少了一些语言的复杂度,但是去带来了一些麻烦事情,就好比.equals和==。孰优孰劣,很难说。
    贫血的“滥用”,我不敢说我没有,因为我并不擅长设计,我很多时候只会自作聪明地发明一些有点怪异的方法。




    我是说这个词。。。:)

    因为我之前就讨伐过这个词,凭什么对象都要有行为。没行为的对象也是对象,贫血一词不准确不贴切也不恰当。

  36. JimLiu
    *.*.*.*
    链接

    JimLiu 2009-09-25 10:07:00

    @Ivony...
    我觉得其实也只是这么个说法,相比DDD的拥有丰富行为的实体类对象,DTO的对象的确很“贫血”——相对的。
    因为我并不擅长对文字细节琢磨,所以这个话题,我也很难展开讨论很多东西了。

  37. Ivony...
    *.*.*.*
    链接

    Ivony... 2009-09-25 10:12:00

    JimLiu:
    @Ivony...
    我觉得其实也只是这么个说法,相比DDD的拥有丰富行为的实体类对象,DTO的对象的确很“贫血”——相对的。
    因为我并不擅长对文字细节琢磨,所以这个话题,我也很难展开讨论很多东西了。




    很多时候,一个词就会带来很大的问题。

    比如说我们今天在这里,说缺失行为的对象是贫血的,那么会有多少程序员去避免缺失行为的对象呢?

    就像设计模式这个词一样,如果当初不是被翻译成设计模式,而是设计范本或设计样例,又会有今天这样近乎痴狂的追捧么?

    还会有反模式和反范式的说法么?

    跑题了。。。。

  38. 天生傻冒
    *.*.*.*
    链接

    天生傻冒 2009-09-25 11:51:00

    看老赵的博文一个好处就是:评论跟文章一样的精彩...

  39. 老赵
    admin
    链接

    老赵 2009-09-25 13:02:00

    riccc:
    代理方面应当是用Castle的DynamicProxy实现透明代理,要求方法为virtual的确是受限于DynamicProxy的实现机制,但原因仅此而已,跟private field没有任何关系


    要延迟加载用virtual没有问题,但完全可以只virtual映射过的属性,但现在无关属性和方法都需要virtual,这就是问题。
    我说private field的问题是有依据,你看我引用的Davy Brion的文章里就是这个意思,至于有没有其他理由就不清楚了。

  40. 老赵
    admin
    链接

    老赵 2009-09-25 13:05:00

    Ivony...:
    我想,这个问题应该改成,NHibernate到底有什么不可替代的东西。


    我想用ORM的功能,方便数据操作啊。

  41. riccc
    *.*.*.*
    链接

    riccc 2009-09-25 14:08:00

    @Jeffrey Zhao
    看了下Davy Brion的文章和评论,我没有看到Davy有什么抱怨或觉得这是个不可理解的困惑。评论中也有人跟你一样的想法,建议NH仅针对需要lazy loading的属性使用virtual,Davy给出了他的看法觉得还是没有必要这样

    另外从那篇文章的评论中你有没有发现,有反对倾向的都是对NH不是很了解的人

    最后,从你的文章中,我没有找到非lazy load属性使用virtual后真正的问题所在是什么,也许跟很多人一样只是一种对"bad smell"的感觉吧,Davy文中也有比较,相对于其他透明lazy load实现方案的缺点来说,这个也不算是什么问题了

    我在用nh的时候倒是因为透明代理出现过不少问题,而不仅仅是一些"感觉"上的东西,但设计就是这样,权衡利弊他还是非常优秀的,设计上的方方面面他都考虑的很周全了提供了各种解决方案,其他各种缺陷或小问题都有不错的solution或workaround,这已经很满意了

  42. 老赵
    admin
    链接

    老赵 2009-09-25 14:25:00

    @riccc
    Davy Brion是NH的开发人员,他是在阐述NH这么做的原因,不是在抱怨……
    的确,你说把它们都表成virtual有没有问题?问题很小,Java语言用户不都这么用下来了吗?
    至于你说“有反对倾向的都是对NH不很了解的人”,这个逻辑是有问题的,不能通过针对对方个人来证明他们提出的就是错误的,要针对话题来说。

    我在另一片文章里就阐述了,我不喜欢什么都是virtual,virtually everything是一种设计上的问题。
    NH让我强制让我出现这种bad smell,这就是我抱怨的地方。

    Davy文字中说其他Lazy Load实现的缺点,我认为他这里也有逻辑问题,这个问题是“虚假两分”。
    因为对于Lazy Load来说,并不是只有“要么全部virtual”,要么“用其他弄脏model”的方式。
    他认为“全部virtual”没有错的理由,不应该是“其他弄脏model的方式不好”,因为我认为完全有更好的做法(局部virtual)。

    设计的确是权衡,需要wordaround。但我的看法是,这里的设计是有问题的,完全不必这样,这是我抱怨的地方。
    但是抱怨之余,我并没有建议别人不要使用NH,何况在此之前我就说了NH是目前最好的ORM框架。
    因此,我也承认NH是非常优秀的,但是优秀又如何呢?我还是认为在virtual问题上,NH的做法不妥当。

  43. 我厂制造
    *.*.*.*
    链接

    我厂制造 2009-09-25 14:59:00

    @Jeffrey Zhao
    C#的属性虽好,但是并没有一种机制能保证程序员不使用私有字段而全都改用属性(而且字段和属性从设计上来讲还是具有不同层面的意义的,也不应该强制完全不使用字段吧),这样对于NH来说,总是存在某个成员可能绕开属性直接访问私有字段的隐患,这就会导致延迟是延迟了,需要使用数据时却没有从数据库加载出来的尴尬.
    如果NH对这种情况放任不管,那么entity对象的数据没有从数据库加载出来就直接给客户端使用,会产生种种不可预知而用户又不易察觉的错误和异常.所以NH也没办法,必须管,就只能强制拦截所有成员,保证任何成员在使用数据时必须先吧数据从数据库加载出来,这样至少NH能保证只要遵循我的约束,客户端就不必担心所使用的实体对象的数据没有从数据库加载出来
    个人觉得,既然要为了被拦截而设置为virtual,就说明entity已经向orm框架屈服了,这里的virtual已经不是设计上的意义而是为了框架的需要而开的后门,因此virtual一部分和virtual全部成员,从Persistence Ignorance的角度来说来并没有多大差别.其实相比entity继承自orm提供的基类或接口的方式,NH的entity只需virtual一下成员,已经是很PI了,何必为了多virtual几个成员耿耿于怀呢.

  44. Ivony...
    *.*.*.*
    链接

    Ivony... 2009-09-25 15:10:00

    我厂制造:
    @Jeffrey Zhao
    C#的属性虽好,但是并没有一种机制能保证程序员不使用私有字段而全都改用属性(而且字段和属性从设计上来讲还是具有不同层面的意义的,也不应该强制完全不使用字段吧),这样对于NH来说,总是存在某个成员可能绕开属性直接访问私有字段的隐患,这就会导致延迟是延迟了,需要使用数据时却没有从数据库加载出来的尴尬.
    如果NH对这种情况放任不管,那么entity对象的数据没有从数据库加载出来就直接给客户端使用,会产生种种不可预知而用户又不易察觉的错误和异常.所以NH也没办法,必须管,就只能强制拦截所有成员,保证任何成员在使用数据时必须先吧数据从数据库...




    这就是Java和.NET的文化的显著差别了。

    显然我是被微软惯坏的孩子,因为我连没有一种机制使得我们能简单的允许某些代码在一个类型里被注入(例如显式的Attribute声明),而必须像这样手动写成virtual都觉得很不爽而耿耿于怀。就更别说对没有这种必要的成员设置virtual了。

  45. 老赵
    admin
    链接

    老赵 2009-09-25 15:13:00

    @我厂制造
    嗯,要求提供基类的方式是不太妥当,NH的做法比它们自然要好不少。
    我对NH强制virtual的做法意见比较大的原因,可能是在于我为DDD设计的模型,为了NH需要有许多修改。
    我觉得在目前的条件下,还做不到让我满意的PI(我不是指绝对的PI),virtual的问题是小事,但NH关于集合的操作,让我感觉这PI其实挺像一个梦的。

  46. 我厂制造
    *.*.*.*
    链接

    我厂制造 2009-09-25 15:38:00

    @Jeffrey Zhao
    我也有关注DDD在.NET平台上的实践,也感觉领域层对象总是不得不受到orm或其他基础设施框架的腐蚀很难成为纯粹的poco.希望有机会能看到赵师傅结合orm框架写些DDD on .NET的实践文章

  47. Ivony...
    *.*.*.*
    链接

    Ivony... 2009-09-25 16:39:00

    我厂制造:
    @Jeffrey Zhao
    我也有关注DDD在.NET平台上的实践,也感觉领域层对象总是不得不受到orm或其他基础设施框架的腐蚀很难成为纯粹的poco.希望有机会能看到赵师傅结合orm框架写些DDD on .NET的实践文章




    就我的观点而言,既然是DDD(领域驱动设计)就应当抛弃ORM或者ERM(Entity-Relation Mapping)的幻想。因为领域对象绝大多数情况下与Entity或者关系数据是有显著差异的。既然是领域驱动,则关系数据不能满足领域对象模型时,就应当抛弃关系数据模型,而不是把领域对象削足适履的费劲的Mapping到关系数据。

  48. 老赵
    admin
    链接

    老赵 2009-09-25 17:08:00

    @Ivony...
    不过就我看来,这也是没有办法的,因为关系型数据库还是最成熟的存储方式,因此它几乎已经是不二之选了。
    而ORM是一种设法缓解领域模型与关系型存储之间差距的方式,最理想的情况下应该由ORM完全实现这种存储逻辑。
    如果ORM能力不足,那么应该提高ORM的能力。但是现状是,ORM真达不到那种能力,而要满足“理想状态”付出的代价太高了。因此,只得“削足适履”地改造领域模型了。
    如果抛弃关系型存储,那么我们又该存在什么地方呢?那种存储成熟吗?他真能满足纯粹的领域模型吗?是不是我们还需要在其他方面让步呢?
    权衡阿,没有办法。

  49. riccc
    *.*.*.*
    链接

    riccc 2009-09-25 21:56:00

    @Jeffrey Zhao
    我理解你的想法,我的出发点是不必这么执着于技术、实现层面上的唯美效果
    理念上有些东西会告诉我"这里的设计是有问题的",如果nh支持仅对那些需要lazy load的属性设置virtual,我也不会滥用,Davy说了即使nh支持这种方式也会产生其他问题(好像是说并非由nh产生的),我们还是要受到一些约束或者workaround。其一沿着这些点追究下去也许是一条没有尽头的路,其二大部分用nh做的都是非研究、前沿、底层性质的东西,在这样的领域他并非一个critcal的问题,我们的重点也并非在这些方面,而有其他更重要的东西需要重点关注和考虑
    这是我的立场,于我而言并不存在喜欢、不喜欢、认同、否定这样的判定

    其实这些讨论已经偏离了我最初回复的内容,开始看到文章中的"让我觉得无厘头了"、"因此,如果是你的话,在写Java代码的时候,是愿意使用getXxx()这样的方法,还是直接访问类中的私有字段?因此我认为,是Java语言的特性,导致Java开发人员倾向于直接访问类中的私有字段,从而导致Hibernate需要避免未加载的私有字段,进一步导致Hibernate的代理类会去覆盖所有的公开方法",只是想为这些说法辩护一下而已,hibernate在设计方面是考虑得细而全的,并非由于这样简单的原因而做出设计决策。我想这个问题在java社区里面同样存在,尽管他的方法默认是virtual的,我猜为了支持lazy load是不能改为final的

  50. riccc
    *.*.*.*
    链接

    riccc 2009-09-25 21:57:00

    @Jeffrey Zhao
    e,这个DDD的理解跟我的理解也有很大的差别

  51. 老赵
    admin
    链接

    老赵 2009-09-25 22:09:00

    @riccc
    只是我想来想去,最能解释的通的便是这个理由,尤其是看了Davy的解释之后,呵呵。
    因为我在C#之前也作了近3年的Java程序员,对于使用私有字段和C#中的属性的倾向性有切身体会——尤其是C#出现自动属性之后,差别愈发明显了。
    Java里肯定也是不能加final的,因为lazy load机制其实差不多。但是因为默认virtual,所以大家“自然”就适应了Hibernate的方式,也没有什么意见了。
    程序员就是这样,都是会去“适应”语言提供的特性,找出最方便的用法:既然嫌getXxx烦,就直接用私有字段了。
    同理,Java既然默认virtual,我看过不少Java代码,发现也几乎不会有人会刻意为某个成员去加上final,

  52. 老赵
    admin
    链接

    老赵 2009-09-25 22:09:00

    riccc:
    @Jeffrey Zhao
    e,这个DDD的理解跟我的理解也有很大的差别


    上一个话题和个人审美情趣比较有关,不如具体谈谈这方面?

  53. Vincent
    *.*.*.*
    链接

    Vincent 2009-09-26 01:47:00

    如果这样设置<hibernate-mapping default-lazy="false">就无需到处声明方法为virtual了.

  54. 老赵
    admin
    链接

    老赵 2009-09-26 01:54:00

    @Vincent
    我们讨论的前提是lazy吧……

  55. 紫色阴影
    *.*.*.*
    链接

    紫色阴影 2009-09-26 02:32:00

    不是说给entity加上行为就叫DDD了,也许能算成充血
    如果仔细看看eric evan的书,会发现DDD的重点并不在这
    它更趋向于分析/设计的一种方法学 而非浅层次的东西
    比如strategic design算是DDD的档次提升和精华点,但是很少有人看DDD会讨论这个 无非每天都在说entity,value object, repository等 甚至还讨论repository和dao的区别 唉。。。

    ORM也只是一种思想,还有很多更好的,多了解了解不会有坏处。 还有很多好的概念,比如make roles explicit, CQS等,都是很有创意,很实用的东西

  56. 老赵
    admin
    链接

    老赵 2009-09-26 02:57:00

    @紫色阴影
    我看了看,其实我和别人也没有说给entity加上行为就叫DDD了。不过通过DDD设计出的模型,entity由于职责所在,很多时候不可避免地会包含行为逻辑。

  57. Ivony...
    *.*.*.*
    链接

    Ivony... 2009-09-26 23:00:00

    紫色阴影:
    不是说给entity加上行为就叫DDD了,也许能算成充血
    如果仔细看看eric evan的书,会发现DDD的重点并不在这
    它更趋向于分析/设计的一种方法学 而非浅层次的东西
    比如strategic design算是DDD的档次提升和精华点,但是很少有人看DDD会讨论这个 无非每天都在说entity,value object, repository等 甚至还讨论repository和dao的区别 唉。。。

    ORM也只是一种思想,还有很多更好的,多了解了解不会有坏处。 还有很多好的概念,比如make roles explicit, CQS等,都是很有创意,很实用的东西




    我不太清楚Entity的定义,但在我的概念中,Entity就应该是没有行为的。
    但Domain Object(领域对象)却是几乎不可能没有行为的(不排除的确没有行为的领域对象),所以Domain Object和Entity之间就存在不能调和的矛盾。

  58. zhchang
    *.*.*.*
    链接

    zhchang 2009-09-27 14:27:00

    最近在看一个叫OpenAccess的ORM框架,发现一个最大的优点就是可以反向或者正向生成,一般的ORM都是数据库到代码,这个框架可以代码到数据库

  59. 老赵
    admin
    链接

    老赵 2009-09-27 14:52:00

    @zhchang
    NHibernate也是可以的,Entity Framework也是可以的。

  60. 迭戈_Forever
    *.*.*.*
    链接

    迭戈_Forever 2009-09-28 10:58:00

    用了半年多的NHibernate,感觉很不错。但是对于Domain及其Mapping配置很麻烦,尤其是表之间的关系复杂,或者存在联合主键的时候。
    还有一个问题,大家谁在用Spring.net。

  61. 老赵
    admin
    链接

    老赵 2009-09-28 11:02:00

    @迭戈_Forever
    看一下Fluent NHibernate吧。

  62. 爬山虎
    *.*.*.*
    链接

    爬山虎 2009-09-30 16:17:00

    @zhchang
    我现在用NH,就是用的代码到数据库的

  63. 推土机soft
    *.*.*.*
    链接

    推土机soft 2009-10-28 04:31:00

    @迭戈_Forever

  64. 迭戈_Forever
    *.*.*.*
    链接

    迭戈_Forever 2009-10-29 08:40:00

    @推土机soft
    可以交流一下。。。

  65. Jiger
    76.118.106.*
    链接

    Jiger 2010-07-19 06:36:56

    听说NHibernate好多年,没有用过,不过最近学习ADO.NET Entity Framework,发现类似的virtual关键字的疑问。看了一些文章才知是Lazy-loading 和tracing的需要。

    For change tracking proxies:Each property that is mapped to a property of an entity type in the data model must have non-sealed, public, and virtual get and set accessors. For lazy loading proxies:Each navigation property must be declared as public, virtual, and not sealed get accessor.

    http://msdn.microsoft.com/en-us/library/dd468057.aspx

  66. 老赵
    admin
    链接

    老赵 2010-07-19 09:58:36

    @Jiger

    “用virtual”和“强制每个都要virtual”是两个概念

  67. DYStudio.Net
    116.247.110.*
    链接

    DYStudio.Net 2011-05-26 19:53:44

    拜读~~~字数太少了,不让提交,补几个吧~~~~

  68. dvevrev
    111.0.225.*
    链接

    dvevrev 2011-09-16 21:12:06

    学习了,果然是好东西

发表回复

登录 / 登录并记住我 ,登陆后便可删除或修改已发表的评论 (请注意保留评论内容)

昵称:(必填)

邮箱:(必填,仅用于Gavatar

主页:(可选)

评论内容(大于5个字符):

  1. Your Name yyyy-MM-dd HH:mm:ss

使用Live Messenger联系我