我们什么时候应该选择nHibernate而不是其他ORM?

Mil*_*ric 8 nhibernate hibernate

我承认,我没有完全理解*Hibernate.

由于像Dapper这样的微型ORM 可用于满足大多数数据访问需求,那么需要像nHibernate这样的大枪的场景是什么?nHibernate闪耀的情况有哪些例子?要明确的是,我不认为"在不改变代码的情况下切换数据库的能力"太有利了.在八年的编程中,我从来没有真正做到这一点,而且似乎是一个浪费时间的开始.

我愿意接受任何深思熟虑的回应,但这里有一些问题的例子:

  1. 与Dapper相比,查询API何时值得进行映射的额外工作?
  2. 如何以限制开发工作和正常工作的方式利用延迟加载?
  3. 什么时候花时间弄清楚如何批处理语句?
  4. 在什么情况下缓存系统比例如页面输出缓存更好?这只适用于非分布式环境吗?
  5. 像我这样的凡人如何理解nHibernate如何在分布式环境中工作?考虑混合缓存,批处理和无状态会话,并考虑负载平衡的Web服务器如何处理所有这些.

Ale*_*use 8

哇,大问题.不确定只有凡人可以回答它.但我认为你太快速地拒绝"切换数据库的能力".有许多软件包,包括商业软件包和开源软件包,它们能够使用不同的RDBMS作为后备存储.管理用于部署到2个以上数据库平台的SQL可能会成为绝对的噩梦,因此以可预测的方式构建SQL(至少与手写编写相比)是一个巨大的优势.只是扮演魔鬼的拥护者,对于某些数据库平台,我可以看到交易吞吐量的增长使得数据库选择也非常昂贵.大多数ORM都会以这种或那种方式帮助您解决这个问题 - 尽管当您的数据库需求足够复杂时,拥有丰富的查询API可能会有很长的路要走.

我认为简短的答案是,当您的数据库需求达到一定程度的复杂性时,满足您的需求的成本会低于nhibernate学习曲线所涉及的成本.我无法提供完整的答案,但会尝试对您的列表项进行思考.

  1. 当你做的不仅仅是CRUD.在多个数据库平台上进行复杂查询的需求可能就是一个很好的例子.在这种类型的应用程序上,你几乎可以最终维护两个独立的代码库(好吧,如果你去存储的proc路由它们真的会分离)并且将所有代码保存在.net中是有价值的(能够单元化是很好的)例如,使用其余代码测试这些查询.
  2. 除了在中等信任环境中看到的问题之外,我不确定延迟加载到底是什么"只是工作".在我眼中,懒惰加载的唯一问题是你需要注意它以避免在获取大量数据时可能带来的一些问题,主要是N + 1选择问题.
  3. 您不需要弄清楚如何批处理语句 - 您只需要设置配置值并忘记它.这是一个非常巨大的优化,NHibernate以最小的努力为您完成 - 当您的代码仅与操作和事务控制直接相关时,您的代码可以更加清晰.
  4. 当您为不同的用户呈现不同的页面或在域图层中执行任何类型的非平凡处理时,缓存返回的数据会非常有用.即使在基本场景中,使用页面输出缓存,您最终可能会在缓存中拥有编辑页面,详细信息页面等,而将数据缓存到更靠近源的位置时,您只需要缓存实体一次.靠近源缓存还可以为您提供更多保护,使其无法提供过时的数据.面向数据的缓存还可以通过服务或通过将nHibernate指向进程外存储(如memcached或redis)在多个应用程序之间共享.这在某些环境中非常有价值.
  5. 我不确定你需要了解它是如何工作的(很多时候我使用开源库来保护自己不需要理解这种事情的实现细节).但简短的回答是,除了缓存(并且只有第二级缓存)之外,在分布式场景中,这些都没有任何不同.只要您使用分布式缓存提供程序(或将所有服务器指向同一个进程外缓存提供程序),您也应该在这方面做得很好.

我只是谈到nHibernate,但我想Hibernate的故事大致相同.对于更大规模,更复杂的应用程序,可以带来很多好处,但是为了获得这个好处,还需要承担很多额外的复杂性 - 它仍然可能不如将自己的解决方案应用于所有问题那么复杂*Hibernate为您解决.

你似乎也有很多关于缓存的问题.我建议阅读这个链接,以了解第一级和第二级缓存的工作原理.我不会试图在这里解释,因为听起来你是在深入了解我可以适应这个已经冗长的回复:)


Ran*_*den 5

NHibernate既强大又强大,但您不必了解它的一切就能成功使用它.回答你的问题:

  1. 所有.NET micro-ORMS都没有我所知道的LINQ支持,而是依赖于在代码中混合使用SQL字符串.使用LINQ构建查询为您提供类型安全性,编译时检查和极佳的可重构性.如果所有查询都使用SQL字符串,请尝试使用数千个查询重构代码库... yikes!通过重构,我的意思就像添加新列,新表等一样简单,这是在企业环境中一直发生的事情.重构字符串是可能的,那就是人们仍然需要做的依赖存储过程的东西,但是如果我有类型安全的话,我肯定不会选择这样做.

  2. 使用延迟加载时,您唯一需要记住的是创建SELECT N + 1场景.每当你有代码在域对象/实体上执行foreach循环时,请确保填充对象的查询使用.Fetch()方法,该方法只是在SQL中创建JOIN并填充所有子对象.否则,当您遍历对象并插入任何子对象时,ORM将必须执行另一个SELECT语句来"获取"数据.基本上,在NHibernate术语中,渴望获取是你的朋友.

  3. 批处理与NHibernate一样简单.在你的NHibernate配置中,打开批处理就是这样.之后,如果确实需要,可以在运行时调整特定查询的批处理大小.

  4. 我自己从未使用过二级缓存.我在一个大型企业环境中工作,我们的应用程序运行速度非常快,无需缓存.NHibernate中的第一级缓存虽然不需要配置,但可以简单地将其视为更改跟踪.基本上,内部NHibernate会保存一个字典,其中包含已从数据库中检索的对象以及要在数据库中保存/更新的对象.第一级缓存是我从未真正想过的东西,但我想在最基本的层面知道它是如何工作的.

  5. 同样,我目前在企业环境中工作,我们有各种使用NHibernate的应用程序; 一些非常基本的和其他使用NHibernate提供的所有强大功能.我通常在我的经验中看到的是,并非团队中的每个成员都需要成为NHibernate专家.通常情况下,1-3个开发人员将非常了解,其他人都不会担心它,只需创建他们的实体,映射,并继续他们的编程.一旦基础设施到位并且您的组织已经整理出它希望使用的模式,一切都是轻而易举的.

其他想法:

NHibernate真正发挥作用的一个地方就是能够映射你抛出的任何疯狂的数据库设计.现在我并不是说在90年代早期将一些疯狂的数据库设计映射到一起很容易,你必须将存储过程和另一个表连接在一起,但这可能的.我在那一天做了一些疯狂的映射.有些人甚至认为这是不可能的,因为数据库并不是为了做我们想做的事情而设计的,但每次使用持久性,我仍然设法通过NHibernate在映射好的和坏的数据库设计方面具有令人难以置信的灵活性.

使用Micro-ORMS,您通常会在代码中嵌入大量SQL字符串.这怎么被认为是干净和有效的.看起来所有人都在做的就是将他们用来存储过程放在他们的代码中.我实际上在我的一些项目中使用Micro-ORM虽然它有意义,但通常当我只在一个表上查询一些简单的数据时 - 没有复杂的WHERE子句.

公平地说,我是那些投入了大量时间学习NHibernate的来龙去脉的人之一,但不是因为我需要工作,而是因为我只是想.我和很多工作的人一起工作,他们每天都在使用NHibernate并且没有完全掌握它.但同样,他们不需要.你只需要了解一些基本的东西就可以了.

希望这可以帮助.