在我的学徒期间,我已经将NHibernate用于一些较小的项目,我自己编写和设计.现在,在开始一个更大的项目之前,讨论产生了如何设计数据访问以及是否使用ORM层.由于我仍处于学徒阶段,并且仍然认为自己是企业编程的初学者,我并没有真正尝试推动我的观点,即使用对象关系映射器到数据库可以大大简化开发.开发团队中的其他程序员比我经验丰富,所以我想我会按照他们的说法去做.:-)
但是,我不完全理解不使用NHibernate或类似项目的两个主要原因:
可以使用SQL查询构建自己的数据访问对象,并将这些查询复制出Microsoft SQL Server Management Studio.
调试ORM可能很难.
所以,当然我可以用很多SELECT
s等构建我的数据访问层,但是在这里我会错过自动连接,延迟加载代理类的优势以及如果表获得新列或列获得更低的维护工作量重命名.(更新众多SELECT
,INSERT
并且UPDATE
查询与更新映射配置,并可能重构业务类和DTO的.)
此外,如果您不熟悉框架,使用NHibernate可能会遇到无法预料的问题.例如,这可能是信任Table.hbm.xml,您可以在其中设置字符串的长度以自动验证.但是,我也可以想象一下基于"简单"SqlConnection查询的数据访问层中的类似错误.
最后,上面提到的那些论点真的是不利用ORM用于基于数据库的非平凡企业应用程序的理由吗?他/我可能错过了其他可能的争论吗?
(我应该补充一点,我认为这就像第一个基于.NET/C#的"大型"应用程序需要团队合作.在Stack Overflow上被认为非常正常的良好实践,例如单元测试或持续集成,都是非 - 到现在为止.)
简短的回答是肯定的,有很好的理由.事实上,有些情况下您无法使用ORM.
例如,我在大型企业金融机构工作,我们必须遵循许多安全准则.为了满足我们的规则和规定,通过审核的唯一方法是在存储过程中保持数据访问.现在有些人可能会说这很愚蠢,但老实说事实并非如此.使用ORM工具意味着工具/开发人员可以插入,选择,更新或删除他或她想要的任何内容.存储过程提供了更高的安全性,尤其是在处理客户端数据时的环境中.我认为这是最重要的考虑因素.安全.
ORM的最佳点
ORM对于自动执行适用的95%以上的查询非常有用.它们的特殊优势在于您拥有一个具有强大对象模型体系结构的应用程序和一个与该对象模型完美匹配的数据库.如果您正在进行新的构建并且在团队中拥有强大的建模技能,那么使用ORM可能会获得良好的结果.
您可能会有一些手动更好的查询.在这种情况下,不要害怕编写一些存储过程来处理这个问题.即使您打算在多个DBMS平台上移植您的应用程序,依赖于数据库的代码也只占少数.请记住,您需要在您打算支持它的任何平台上测试您的应用程序,对某些存储过程进行一些额外的移植工作不会对您的TCO产生很大影响.对于第一个近似值,98%的便携式设备与100%的便携式设备一样好,远远优于复杂或性能不佳的解决方案,可以在ORM的极限范围内工作.
我已经看到前一种方法在一个非常大的(100年的员工年)J2EE项目中运行良好.
ORM可能不是最合适的地方
在其他情况下,可能存在比ORM更适合应用的方法.Fowler的企业应用程序架构模式有一个关于数据访问模式的部分,它可以很好地编写各种方法.我见过ORM可能不适用的情况的一些例子是:
在具有存储过程的大量遗留代码库的应用程序上,您可能希望使用功能导向(不要与功能语言混淆)数据访问层来包装现有的sprocs.这将重用现有的(因此经过测试和调试的)数据访问层和数据库设计,这通常代表了相当大的开发和测试工作,并节省了将数据迁移到新数据库模型的麻烦.将Java层包装在传统的PL/SQL代码库中,或者使用Web界面重新定位富客户端VB,Powerbuilder或Delphi应用程序通常是一种非常好的方法.
变体是您继承不一定非常适合OR映射的数据模型的地方.如果(例如)您正在编写一个填充或从外部接口提取数据的接口,那么最好不要使用数据库直接工作.
跨金属应用程序或其他类型的系统,其中跨系统数据完整性很重要,特别是如果您使用具有两阶段提交的复杂分布式事务.您可能需要比ORM能够支持的更好地管理您的交易.
您希望真正调整数据库访问的高性能应用程序.在这种情况下,可能优选在较低水平下工作.
您正在使用ADO.Net这样的现有数据访问机制,即"足够好"且与平台良好协作的情况比ORM带来的好处更大.
有时数据只是数据 - 例如,您的应用程序正在使用"事务"而不是"对象",并且这是域的合理视图.这方面的一个例子可能是财务包,您可以使用可配置的分析字段进行交易.虽然应用程序本身可以构建在OO平台上,但它不依赖于单个业务领域模型,并且可能不仅仅知道GL代码,帐户,文档类型和六个分析字段.在这种情况下,应用程序不知道业务域模型本身,并且对象模型(在分类帐结构本身之外)与应用程序无关.
首先 - 使用ORM不会使您的代码更容易测试,也不一定会在持续集成场景中提供任何优势.
根据我的经验,使用ORM可以提高开发速度,您需要解决的最大问题是:
测试你的代码
维护您的代码
这些解决方案是:
使您的代码可测试(使用SOLID原则)
为尽可能多的代码编写自动化测试
尽可能经常运行自动化测试
提出你的问题,你列出的两个反对意见似乎更像是无知而不是其他任何事情.
无法手动编写SELECT查询(我认为,这就是为什么需要复制粘贴)似乎表明迫切需要一些SQL培训.
我不使用ORM有两个原因:
公司的政策严格禁止(在这种情况下我会去其他地方工作)
该项目非常耗费数据,使用特定于供应商的解决方案(如BulkInsert)更有意义.
关于ORM的常见拒绝(特别是NHibernate)是:
速度
没有理由使用ORM比手动编码数据访问慢.事实上,由于内置的缓存和优化,它可以更快.一个好的ORM将生成一组可重复的查询,您可以为其优化模式.良好的ORM还允许使用各种提取策略有效地检索关联数据.
复杂
关于复杂性,使用ORM意味着更少的代码,这通常意味着更少的复杂性.许多使用手写(或代码生成)数据访问的人发现自己在"低级"数据访问库上编写自己的框架(比如为ADO.Net编写辅助方法).这些等同于更复杂,更糟糕的是,它们很少有很好的文档记录或经过充分测试.
如果你专注于NHibernate,那么像Fluent NHibernate和Linq To NHibernate这样的工具也会减弱学习曲线.
让我了解整个ORM辩论的事情是,那些声称使用ORM的人会太难/慢/无论使用Linq To Sql还是Typed Datasets都非常满意.虽然Linq To Sql是朝着正确方向迈出的一大步,但它仍然落后于一些开源ORM的落后时间.但是,Typed Datasets和Linq To Sql的框架仍然非常复杂,使用它们太远(Table = Class)+(基本CRUD)是非常困难的.
我的建议是,如果在一天结束时,您无法获得ORM,那么请确保您的数据访问与其余代码分开,并且您遵循Gang Of Four的编码建议一个界面.另外,获取一个Dependancy Injection框架来进行连接.
(咆哮怎么样?)
有很多常见的问题,像Hibernate这样的ORM工具是上帝发送的,还有一些是阻碍它的地方.我对你的项目知之甚少,不知道它是什么.
Hibernate的一个优点是你只能说3次:在类,.hbm.xml文件和数据库中提到了每个属性.使用SQL查询,您的属性位于类,数据库,select语句,insert语句,update语句,delete语句以及支持SQL查询的所有编组和解组代码中!这可能会很快变得混乱.另一方面,你知道它是如何工作的.你可以调试它.它可以在你自己的持久层中,而不是埋没在第三方工具的内部.
Hibernate可能是Spolsky的Leaky Abstractions法则的典型代表.稍微偏离常规路径,您需要了解该工具的深层内部工作原理.当你知道你可以在几分钟内修复SQL时,它可能会非常烦人,但你花了好几个小时试图哄骗你的dang工具来生成合理的SQL.调试有时是一场噩梦,但很难说服那些没有去过那里的人.
编辑:你可能想看看iBatis.NET,如果他们不打算转向NHibernate,他们想要控制他们的SQL查询.
编辑2:这里是一个大红旗:"好的做法,在Stack Overflow上看起来很正常,例如单元测试或持续集成,到目前为止还不存在." 那么,这些"经验丰富"的开发人员,他们在开发方面经历了什么?他们的工作安全?听起来你可能是那些对这个领域不特别感兴趣的人,所以不要让他们扼杀你的兴趣.你需要保持平衡.投入了战斗.
近年来,ORM的增长一直在增长,而您经验丰富的同事可能仍在思考"每个数据库调用都应该通过存储过程"的心态.
为什么ORM会使调试变得更难?无论是来自存储过程还是来自ORM,您都会得到相同的结果.
我想我能用ORM想到的唯一真正的不利因素是安全模型的灵活性稍差.
编辑:我只是重新阅读你的问题,看起来他们是复制并将查询粘贴到内联sql.这使得安全模型与ORM相同,因此与ORM相比,这种方法绝对没有优势.如果他们使用的是非参数查询,则实际上存在安全风险.
我在一个没有成功使用ORM的项目上工作过.这是一个项目
从一开始就必须横向扩展
不得不快速发展
有一个相对简单的域模型
让NHibernate在水平分区结构中工作所花费的时间比开发一个了解我们的分区方案的超级简单数据映射器花费的时间要长得多......
因此,我在ORM上工作的90%的项目都是非常宝贵的帮助.但是在某些非常特殊的情况下,我可以看到不使用ORM是最好的.
我首先要说的是,如果正确集成,ORM可以使您的开发生活更轻松,但是有一些问题,ORM实际上可以阻止您实现您声明的要求和目标.
我发现在设计具有高性能要求的系统时,我常常面临着寻找使系统更高性能的方法.很多时候,我最终得到的解决方案具有较高的写入性能(这意味着我们写的数据比我们读取数据的要多得多).在这些情况下,我想利用数据库平台为我提供的设施来实现我们的性能目标(它是OLTP,而不是OLAP).因此,如果我使用的是SQL Server,并且我知道我要编写大量数据,为什么我不会使用批量插入...好吧,正如您可能已经发现的那样,大多数ORMS(我不知道是否即便是一个人也没有能力利用平台特定的优势,如批量插入.
您应该知道可以混合使用ORM和非ORM技术.我刚刚发现有一些边缘情况,ORM无法满足您的要求,您必须为这些情况解决这些问题.
当您需要更新50000000条记录时.设置旗帜或其他什么.
尝试使用ORM执行此操作而不调用存储过程或本机SQL命令.
更新1:尝试仅检索一个只有少数字段的记录.(当你有一个非常"宽"的表).或者是标量结果.ORM也很尴尬.
更新2:似乎EF 5.0 beta承诺批量更新,但这是非常热门的新闻(2012年1月)
特色:
通过不使用ORM,您正在解决已经由大型社区或拥有大量资源的公司反复解决的问题.
通过使用ORM,数据访问层的核心部分可以从该社区或公司的调试工作中受益.
为了在论证中加入一些观点,请考虑使用ADO.NET与编写代码以自行解析表格数据流的优势.
我已经看到无知如何使用ORM证明开发人员对ORM的蔑视例如:渴望加载(我注意到你没有提到的东西).想象一下,您想要检索客户及其所有订单,以及所有订单明细项目.如果你只依赖于延迟加载,那么你将从ORM经验中摒弃以下观点:"ORM很慢." 如果您学习如何使用预先加载,您将在2分钟内完成5行代码,您的同事将花费半天时间来实现:对数据库进行一次查询并将结果绑定到对象层次结构.另一个例子是手动编写SQL查询以实现分页的痛苦.
使用ORM的可能例外是,该应用程序是一个ORM框架,旨在应用专门的业务逻辑抽象,并设计为在多个项目上重用.但是,即使情况如此,通过使用这些抽象增强现有ORM,您也可以更快地采用.
不要让你的高级团队成员的经验把你拉向与计算机科学发展相反的方向.我一直在专业发展23年,其中一个常数是老派对新人的蔑视.ORMs是SQL语言,因为C语言是汇编语言,你可以打赌,C++和C#的等价物正在逐步推进.一行新学校代码相当于20行老派.
我想也许当你在更大的系统上工作时,你可以使用像CodeSmith这样的代码生成器工具而不是ORM ......我最近发现:Cooperator Framework生成SQL Server存储过程并生成业务实体,映射器,网关, lazyload和C#中的所有内容......检查出来......它是由阿根廷的一个团队写的......
我认为编码整个数据访问层并使用ORM之间的中间...
就个人而言,我(直到最近)反对使用ORM,并且习惯于编写封装所有SQL命令的数据访问层.对ORM的主要反对意见是我不相信ORM实现来编写正确的SQL.而且,根据我以前看到的ORM(主要是PHP库)判断,我认为我是完全正确的.
现在,我的大部分Web开发都使用Django,我发现包含的ORM非常方便,并且由于数据模型首先在它们的术语中表达,并且仅在SQL的后期表达,因此它确实完全满足我的需求.我确信它不会太难以超出它并且需要补充手写的SQL; 但对于CRUD访问来说绰绰有余.
我不知道NHibernate; 但我想这对你需要的大部分内容来说也"足够好".但如果其他程序员不相信它; 它将成为每个数据相关错误的主要嫌疑人,使验证更加繁琐.
您可以尝试在工作场所逐步引入它,首先关注小的"明显"应用程序,如简单的数据访问.过了一会儿,它可能会用在原型上,而且可能不会被替换......
如果它是OLAP数据库(例如,用于报告/分析的静态,只读数据等),那么实现ORM框架是不合适的.相反,使用数据库的本机数据访问功能(如存储过程)将更为可取.ORM更适合于事务性(OLTP)系统.