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使用了一种简单的延迟加载方式。例如有这样一个对象:

public class Article
{
public virtual int ArticleID { get; set; }
public virtual string TagNames { get; set; }
}

在延迟加载的时候,我一直以为NHibernate只是通过Emit生成一个Article的子类,然后把属性覆盖成简单读写,例如:

public class Article$LazyProxy : Article
{
private string m_tagNames;
public override string TagNames
{
get
{
return this.m_tagNames;
}
set
{
this.m_tagNames = value;
}
}
}

这么做的问题自然是让TagNames属性原本的逻辑丢失了。如果对于失血的DTO模型,这自然没有关系,因为这些属性本身内部没有逻辑。但是,我习惯使用领域驱动设计(DDD)的方式来为产品建模,因此在这些属性中很可能拥有一些业务逻辑。例如改变对象的其他一些状态,同步至其他字段,或是触发事件等等。因此,丢失属性逻辑对我的影响是致命的,这意味着我必须“照顾”NHibernate的特性进行编程,而在进行建模时就开始考虑持久化逻辑是DDD实践中的一大问题——虽然软件开发不是理想化的,权衡是正常的,但如果NHiberante只能应付失血的DTO模型,那么它就对不起它的业界盛名了。

可惜的是,NHibernate没有在这里翻船——所以可能更应该说“值得庆幸”——它使用了一种维持原有业务逻辑的延迟代理写法:

public class ArticleLazyProxy : Article
{
public override string TagNames
{
get
{
var tagNames = ... // 加载数据
base.TagNames = tagNames;
return base.TagNames;
}
set
{
base.TagNames = value;
}
}
}

当然,这是我从“测试效果”中反推出来的情况,NHiberante的实际做法应该不会那么简单。如果您关注我的文章,会发现这就是我之前提出的最为理想的延迟代理实现方式,也是我在Eazy类库中使用的做法。我在实现了Eazy的基本功能之后,还因为它满足了我的要求而微微沾沾自喜了一把,谁知这一切早已被NHibernate拿下。我昨天晚上试验出这个结果之后也震惊了一把,不是因为NHibernate的强大(因为它本不该犯此低级错误),而是因为我不理解自己之前为什么会轻易地臆断NHibernate的做法?想象我还在多篇文章中抱怨过这点,昨天试验过后,我立即把自己能想到的无稽之谈都修改了。惭愧啊。

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

我对NHibernate的感受(1):对延迟加载方式的误解的更多相关文章

  1. NHibernate 有好几种数据库查询方式

    NHibernate 有好几种数据库查询方式 1.原生SQL var employeeQuery = Database.Session .CreateSQLQuery("select * f ...

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

    上一篇主要是在夸NHibernate实现的好,而这篇就完全是来抱怨的了.NHiberante有个毛病,就是如果是和数据库产生映射的类,就要求所有的public成员和protected成员必须是virt ...

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

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

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

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

  5. [NHibernate]延迟加载

    目录 写在前面 文档与系列文章 延迟加载 一个例子 总结 写在前面 上篇文章介绍了多对多关系的关联查询的sql,HQL,Criteria查询的三种方式.本篇文章将介绍nhibernate中的延迟加载方 ...

  6. NHibernate教程(12)--延迟加载

    本节内容 引入 延迟加载 实例分析 1.一对多关系实例 2.多对多关系实例 结语 引入 通过前面文章的分析,我们知道了如何使用NHibernate,比如CRUD操作.事务.一对多.多对多映射等问题,这 ...

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

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

  8. [NHibernate]立即加载

    目录 写在前面 文档与系列文章 立即加载 一个例子 总结 写在前面 上篇文章介绍了nhibernate延迟加载的相关内容,简单回顾一下延迟加载,就是需要的时候再去加载,需要的时候再向数据库发出sql指 ...

  9. [NHibernate]N+1 Select查询问题分析

    目录 写在前面 文档与系列文章 N+1 Select查询问题分析 总结 写在前面 在前面的文章(延迟加载,立即加载)中都提到了N+1 Select的问题,总觉得理解的很不到位,也请大家原谅,这也是为什 ...

随机推荐

  1. [java笔记]常用的设计模式

    1.单例设计模式 单例设计模式:保证一个类仅有一个实例,并提供一个访问它的全局访问点. 1)构造方法私有化 2)声明一个本类对象 3)给外部提供一个静态方法获取对象实例 例如: class Singl ...

  2. POJ 2516 Minimum Cost(拆点+KM完备匹配)

    题目链接:http://poj.org/problem?id=2516 题目大意: 第一行是N,M,K 接下来N行:第i行有K个数字表示第i个卖场对K种商品的需求情况 接下来M行:第j行有K个数字表示 ...

  3. nginx防止DDOS攻击

    防御DDOS是一个系统工程,攻击花样多,防御的成本高瓶颈多,防御起来即被动又无奈.DDOS的特点是分布式,针对带宽和服务攻击,也就是四层流量攻击和七层应用攻击,相应的防御瓶颈四层在带宽,七层的多在架构 ...

  4. Django API验证(令牌)

    1. 获取接口信息 Client端 import requests import time import hashlib ctime = time.time() key = 'akfljakfjakl ...

  5. JS正则表达式方法

    使用正则表达式的主要有match,exec,test 1.正则表达式方法test测试给定的字符串是否满足正则表达式,返回值是bool类型的,只有真和假. var user_code = $(" ...

  6. day8--by a gentlement man

    1.着装得体(不要国产.不要Jack&Johnson.selected),人都是势利眼,高素质和低素质人的区别,高素质是心里明白歧视你,但是不说:低素质是直接表示出来:lower,屌丝     ...

  7. bzoj 1271

    思路:因为被占奇数次的点只有一个, 那么我们可以将数轴分成两部分,奇数次点之前的前缀和为偶数,之后的前缀和为奇数, 然后就可以二分了. #include<bits/stdc++.h> #d ...

  8. 虚拟机之openVZ简单基础

    OpenVZ的是免费的开源软件,基于GNU GPL协议. OpenVZ的是基于Linux的容器虚拟化. OpenVZ在一台服务器上能够创建创建多个安全隔离的Linux容器(也称为虚拟环境或的VPS), ...

  9. MVP模型

    MVP模型一般要创建三个文件夹:View.Interactor(Model).Presenter 每个部分都有其接口和实现类,就是为了方便回调 这里做一个登陆界面为例子: 接口: Interactor ...

  10. OpenCV 基础笔记

    本文大部分内容来源于入门者的Python快速教程 - 番外篇之Python-OpenCV 本篇将介绍和深度学习数据处理阶段最相关的基础使用,并完成4个有趣实用的小例子: 延时摄影小程序 视频中截屏采样 ...