找回密码
 立即注册
首页 业界区 业界 我对NHibernate的感受(1):对延迟加载方式的误解 ...

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

溶绚 2025-5-29 20:04:46
NHibernate是.NET平台上最著名的ORM框架,虽说出身于Java平台上的Hibernate,但是从外部看来这几乎就是一个.NET平台上的原生产品:有自己的社区,有自己的用户,有自己的商业支持,有利用C#特性的独立扩展。它不像Lucene.NET那样,一眼就能看出浓重的Java气息,Java的命名方式等等。我用NHibernate时间不长,而NHibernate的复杂程度也决定了我无法像了解LINQ to SQL那样容易。不过在使用了一段时间过后,还是对它有一定体会。有欣喜,有误解,也有抱怨。
这几篇文章里我不打算多谈NHiberante的优点,因为它的优势实在过于明显。如果不考虑Telerik ORM这样的商业框架(因为我没用过,完全不了解),.NET平台上开源和免费的ORM工具几乎没有NHibernate的对手:LINQ to SQL使用的确容易,上手非常快,某些功能也非常细致(稍后会谈到),但对于ORM工具的灵魂“Mapping能力”实在是不敢恭维。前一段时间我也简单了解了一下微软新出的Entity Framework,虽然也秉承了微软一贯的易用性(如强大的LINQ支持),在Mapping能力上也有切实的提高,但是在功能和一些细节控制上还远不如NHibernate。毕竟NHibernate是经历了多年发展,对于各种情况几乎都有应对措施。如延迟与否,是使用select还是join获取数据,是否在集合加载时附加条件。此外,NHibernate的Interceptor能力所带来的扩展性也是让我比较满意的,不过这点有机会再详细谈一下。
总之,目前NHibernate是我最满意的ORM框架。
那么现在进入正文内容。首先我想谈一下自己对NHibernate实现方式上的一个误解,这个误解让我对NHibernate一直有着错误的抱怨,我还在几篇文章里不断重复对NHibernate的错误指责,目前已经纠正,希望不会造成太大问题。
这个误解,是我一直认为NHibernate使用了一种简单的延迟加载方式。例如有这样一个对象:
  1. public class Article
  2. {
  3.     public virtual int ArticleID { get; set; }
  4.     public virtual string TagNames { get; set; }
  5. }
复制代码
在延迟加载的时候,我一直以为NHibernate只是通过Emit生成一个Article的子类,然后把属性覆盖成简单读写,例如:
  1. public class Article$LazyProxy : Article
  2. {
  3.     private string m_tagNames;
  4.     public override string TagNames
  5.     {
  6.         get
  7.         {
  8.             return this.m_tagNames;
  9.         }
  10.         set
  11.         {
  12.             this.m_tagNames = value;
  13.         }
  14.     }
  15. }
复制代码
这么做的问题自然是让TagNames属性原本的逻辑丢失了。如果对于失血的DTO模型,这自然没有关系,因为这些属性本身内部没有逻辑。但是,我习惯使用领域驱动设计(DDD)的方式来为产品建模,因此在这些属性中很可能拥有一些业务逻辑。例如改变对象的其他一些状态,同步至其他字段,或是触发事件等等。因此,丢失属性逻辑对我的影响是致命的,这意味着我必须“照顾”NHibernate的特性进行编程,而在进行建模时就开始考虑持久化逻辑是DDD实践中的一大问题——虽然软件开发不是理想化的,权衡是正常的,但如果NHiberante只能应付失血的DTO模型,那么它就对不起它的业界盛名了。
可惜的是,NHibernate没有在这里翻船——所以可能更应该说“值得庆幸”——它使用了一种维持原有业务逻辑的延迟代理写法:
  1. public class ArticleLazyProxy : Article
  2. {
  3.     public override string TagNames
  4.     {
  5.         get
  6.         {
  7.             var tagNames = ... // 加载数据
  8.             base.TagNames = tagNames;
  9.             return base.TagNames;
  10.         }
  11.         set
  12.         {
  13.             base.TagNames = value;
  14.         }
  15.     }
  16. }
复制代码
当然,这是我从“测试效果”中反推出来的情况,NHiberante的实际做法应该不会那么简单。如果您关注我的文章,会发现这就是我之前提出的最为理想的延迟代理实现方式,也是我在Eazy类库中使用的做法。我在实现了Eazy的基本功能之后,还因为它满足了我的要求而微微沾沾自喜了一把,谁知这一切早已被NHibernate拿下。我昨天晚上试验出这个结果之后也震惊了一把,不是因为NHibernate的强大(因为它本不该犯此低级错误),而是因为我不理解自己之前为什么会轻易地臆断NHibernate的做法?想象我还在多篇文章中抱怨过这点,昨天试验过后,我立即把自己能想到的无稽之谈都修改了。惭愧啊。
哎,莫装B,装B被雷劈。
相关文章


  • 我对NHibernate的感受(1):对延迟加载方式的误解
  • 我对NHibernate的感受(2):何必到处都virtual
  • 我对NHibernate的感受(3):有些尴尬的集合支持
  • 我对NHibernate的感受(4):令人欣喜的Interceptor机制

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册