Nhibernate开发专题博客

Nhibernate开发专题博客,为您精选Nhibernate开发教程,助您开发愉快!

公告信息
欢迎光临Nhibernate开发专题博客,祝您开发愉快!
文章档案

为何NHibernate延迟加载到处用virtual属性

NHiberante为了延迟加载,对于数据库产生映射的类,所有的public和protected成员必须是virtual的,不公是属性,连没有映射关系的也需要virtual限制,只为延迟加载?

    正如以下提示:

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

      直到看了NHibernate开发团队成员Davy Brion的文章《Must Everything be Virtual with NHiberante?》之后,我才了解了他们的设计思路。

      要求类中所有的公开成员(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,无论是方法还是属性。

      为此,大伙不得不用到处用virtual,总感觉有点不爽!!!

    新浪微博粉丝精灵,刷粉丝、刷评论、刷转发、企业商家微博营销必备工具"

    2011/9/30 14:41:35 | Nhibernate开发教程 | |

    • 发表评论