是否有充分的理由不使用ORM
本文关键字:ORM 理由 是否 | 更新日期: 2023-09-27 17:48:48
在我的学徒生涯中,我在一些较小的项目中使用了NHibernate,这些项目大多是我自己编码和设计的。现在,在开始一些更大的项目之前,讨论了如何设计数据访问以及是否使用ORM层。由于我还在学徒期,仍然认为自己是企业编程的初学者,所以我并没有真正尝试推动我的观点,即使用对象关系映射器到数据库可以大大简化开发。开发团队中的其他程序员比我更有经验,所以我想我会按照他们说的去做。:-)
然而,我并不完全理解不使用NHibernate或类似项目的两个主要原因:
- 可以使用SQL查询构建自己的数据访问对象,并将这些查询复制到Microsoft SQL Server Management Studio之外
- 调试ORM可能很困难
因此,我当然可以用大量的SELECT
等构建我的数据访问层,但这里我忽略了自动联接、延迟加载代理类的优点,以及如果表获得了新列或列被重命名,则维护工作量更低。(更新大量SELECT
、INSERT
和UPDATE
查询与更新映射配置以及可能重构业务类和DTO相比。)
此外,使用NHibernate,如果您不太了解框架,您可能会遇到无法预见的问题。例如,这可以是信任Table.hbm.xml,在该表中您设置了要自动验证的字符串长度。然而,我也可以想象在"简单"的基于SqlConnection查询的数据访问层中出现类似的错误。
最后,上面提到的这些论点真的是不将ORM用于基于数据库的非平凡企业应用程序的好理由吗?他们/我可能遗漏了其他论点吗?
(我可能应该补充一点,我认为这就像第一个基于.NET/C#的"大"应用程序,需要团队合作。到目前为止,在Stack Overflow上被视为非常正常的良好实践,如单元测试或连续集成,在这里还不存在。)
简短的回答是肯定的,确实有充分的理由。事实上,在某些情况下,您无法使用ORM。
举个例子,我在一家大型企业金融机构工作,我们必须遵守很多安全准则。为了满足强加给我们的规则和条例,通过审核的唯一方法是将数据访问保留在存储过程中。现在有些人可能会说这很愚蠢,但老实说,事实并非如此。使用ORM工具意味着工具/开发人员可以插入、选择、更新或删除他或她想要的任何内容。存储过程提供了更多的安全性,尤其是在处理客户端数据的环境中。我认为这是考虑的最大理由。安全
ORMs的最佳点
ORM对于自动化95%以上的查询非常有用。它们的特殊优势在于,您有一个具有强大对象模型体系结构的应用程序和一个与该对象模型配合良好的数据库。如果你正在进行新的构建,并且你的团队中有很强的建模技能,那么你可能会通过ORM获得好的结果。
您可能会有一些查询,这些查询最好手动完成。在这种情况下,不要害怕编写一些存储过程来处理此问题。即使你打算在多个DBMS平台上移植你的应用程序,依赖数据库的代码也只是少数。请记住,您需要在任何打算支持应用程序的平台上测试它,为一些存储过程做一点额外的移植工作不会对您的TCO产生太大影响。对于第一个近似值,98%的可移植性与100%的可移植性能一样好,并且远优于复杂或性能较差的解决方案,以绕过ORM的限制。
我已经看到前一种方法在一个非常大的(100多年的员工)J2EE项目中运行得很好。
ORM可能不是最适合的
在其他情况下,可能存在比ORM更适合应用程序的方法。Fowler的企业应用程序架构模式中有一节介绍了数据访问模式,它很好地对各种方法进行了编目。我看到的一些ORM可能不适用的情况的例子是:
-
在具有大量存储过程遗留代码库的应用程序上,您可能希望使用面向功能(不要与功能语言混淆)的数据访问层来包装现有存储过程。这重新使用了现有的(因此经过测试和调试的)数据访问层和数据库设计,这通常代表着相当大的开发和测试工作量,并节省了将数据迁移到新数据库模型的成本。这通常是一种很好的方式,可以将Java层封装在遗留的PL/SQL代码库中,或者用web界面重新定位富客户端VB、Powerbuilder或Delphi应用程序。
-
一种变体是继承不一定非常适合O-R映射的数据模型。如果(例如)您正在编写一个从外部接口填充或提取数据的接口,那么您最好直接使用数据库。
-
跨系统数据完整性很重要的金融应用程序或其他类型的系统,尤其是当您使用具有两阶段提交的复杂分布式事务时。您可能需要比ORM所能支持的更好地对事务进行微观管理。
-
高性能应用程序,您希望真正调整数据库访问。在这种情况下,最好是在较低的级别上工作。
-
在使用像ADO.Net这样的现有数据访问机制的情况下,它"足够好",并且能很好地利用平台,这比ORM带来的好处更大。
-
有时数据只是数据——例如,您的应用程序使用的可能是"事务"而不是"对象",并且这是域的合理视图。这方面的一个例子可能是财务包,其中有带有可配置分析字段的交易。虽然应用程序本身可能构建在O-O平台上,但它并不局限于单个业务领域模型,可能不知道总账代码、账户、文档类型和六个分析字段。在这种情况下,应用程序不知道业务域模型本身,并且对象模型(超出分类帐结构本身)与应用程序无关。
首先,使用ORM不会使代码更容易测试,也不一定会在持续集成场景中提供任何优势。
根据我的经验,虽然使用ORM可以提高开发速度,但您需要解决的最大问题是:
- 测试代码
- 维护代码
这些问题的解决方案是:
- 使代码可测试(使用SOLID原则)
- 为尽可能多的代码编写自动化测试
- 尽可能频繁地运行自动化测试
说到你的问题,你列出的两个反对意见似乎更像是无知。
不能手工编写SELECT查询(我想这就是为什么需要复制粘贴的原因)似乎表明迫切需要一些SQL培训。
我不使用ORM有两个原因:
- 这是公司政策严格禁止的(在这种情况下,我会去其他地方工作)
- 该项目非常数据密集,使用特定于供应商的解决方案(如BulkInsert)更有意义
关于ORM(特别是NHibernate)的常见反驳是:
-
速度
使用ORM没有理由比手动编码的数据访问慢。事实上,由于内置了缓存和优化功能,它可以更快。一个好的ORM将生成一组可重复的查询,您可以优化您的模式。一个好的ORM还将允许使用各种获取策略高效地检索相关数据。
-
复杂度
关于复杂性,使用ORM意味着更少的代码,这通常意味着更低的复杂性。许多使用手写(或代码生成)数据访问的人发现他们自己在"框架"上编写自己的框架;"低电平";数据访问库(比如为ADO.Net编写辅助方法)。这些相当于更复杂,更糟糕的是,它们很少有良好的文档记录或测试
如果你专门研究NHibernate,那么Fluent NHibernat和Linq To NHibernaate等工具也会软化学习曲线。
整个ORM辩论让我感到困惑的是,那些声称使用ORM太难/太慢/什么的人,正是那些非常喜欢使用Linq-To-Sql或Typed数据集的人。虽然Linq-To-Sql是朝着正确方向迈出的一大步,但它仍然落后于一些开源ORM几光年。然而,Typed Dataset和Linq To Sql的框架仍然非常复杂,使用它们来超越(Table=Class)+(基本CRUD)是非常困难的。
我的建议是,如果一天结束时,你无法获得ORM,那么请确保你的数据访问与代码的其他部分分开,并遵循四人帮的建议,对接口进行编码。另外,获得一个依赖性注入框架来进行连接。
(咆哮怎么样?)
有很多常见的问题,像Hibernate这样的ORM工具是天赐之物,也有一些是障碍。我对你的项目了解不够,不知道是哪一个
Hibernate的优点之一是,您只能说3次:每个属性都在类、.hbm.xml文件和数据库中被提及。使用SQL查询,您的属性位于类、数据库、select语句、insert语句、update语句、delete语句以及所有支持SQL查询的编组和解编组代码中!这会很快变得一团糟。另一方面,你知道它是如何运作的。你可以调试它。它就在你自己的持久层中,而不是埋在第三方工具的内部。
Hibernate可能是斯波尔斯基泄漏抽象定律的典型代表。稍微偏离常规,你需要了解该工具的深层次内部工作原理。当你知道你本可以在几分钟内修复SQL,但你却花了几个小时试图哄骗你的该死的工具生成合理的SQL时,这可能会很烦人。调试有时是一场噩梦,但很难说服那些没有去过那里的人。
编辑:你可能想看看iBatis。NET,如果他们不想改变NHibernate,并且他们希望控制他们的SQL查询。
第二版:不过,这是一个大的危险信号:"到目前为止,在Stack Overflow上被视为非常正常的良好实践,如单元测试或持续集成,在这里还不存在。"那么,这些"经验丰富"的开发人员,他们在开发方面有什么经验?他们的工作保障?听起来你可能是对这个领域不太感兴趣的人之一,所以不要让他们扼杀你的兴趣。你需要保持平衡。打一架。
近年来ORM的增长呈爆炸式增长,您更有经验的同事可能仍然认为"每个数据库调用都应该通过存储过程"。
为什么ORM会让调试变得更加困难?无论是来自存储的proc还是来自ORM,都会得到相同的结果。
我想我能想到的ORM唯一真正的缺点是安全模型的灵活性有点低。
编辑:我刚刚重读了你的问题,看起来他们正在将查询复制并粘贴到内联sql中。这使得安全模型与ORM相同,因此与ORM相比,这种方法绝对没有优势。如果他们使用的是未经框架化的查询,那么这实际上是一个安全风险。
我在一个项目中非常成功地不使用ORM。
- 必须从一开始就具有水平可缩放性
- 必须快速开发
- 有一个相对简单的领域模型
让NHibernate在水平分区结构中工作所需的时间将比开发一个了解我们的分区方案的超简单数据映射器所需的更长。。。
因此,在我参与的90%的项目中,ORM是一个宝贵的帮助。但在一些非常具体的情况下,我认为不使用ORM是最好的。
首先让我说,如果集成得当,ORM可以让您的开发生活更轻松,但有一些问题是ORM实际上会阻止您实现所述的需求和目标。
我发现,在设计对性能要求很高的系统时,我经常面临挑战,要找到让系统更具性能的方法。很多时候,我最终会得到一个写性能很高的解决方案(这意味着我们写数据的次数比读数据的次数多得多)。在这些情况下,我想利用数据库平台为我提供的功能来实现我们的性能目标(它是OLTP,而不是OLAP)。所以,如果我使用SQL Server,并且我知道我有很多数据要写,为什么不使用大容量插入。。。好吧,正如您可能已经发现的那样,大多数ORMS(我不知道是否只有一个ORMS)没有能力利用特定于平台的优势,比如大容量插入。
您应该知道,您可以混合ORM和非ORM技术。我刚刚发现,在少数边缘情况下,ORM无法支持您的需求,您必须针对这些情况解决这些问题。
对于一个非平凡的基于数据库的企业应用程序,确实没有理由不使用ORM
除此之外的功能:
- 通过不使用ORM,您正在解决已经存在的问题大型社区或公司反复解决资源
- 通过使用ORM,数据访问层的核心部分将受益来自该社区或公司的调试工作
为了在争论中提供一些观点,请考虑使用ADO.NET与自己编写解析表格数据流的代码相比的优势。
我看到了对如何使用ORM的无知证明了开发人员对ORM的蔑视。例如:热切加载(我注意到你没有提到这一点)。想象一下,你想检索一个客户和他们的所有订单,以及所有订单的详细信息。如果你只依赖于懒惰加载,你会带着这样的观点离开你的ORM体验:"ORM很慢。"如果你学会了如何使用渴望加载,你将在2分钟内完成5行代码,你的同事将花半天时间来实现:一个查询到数据库,并将结果绑定到对象的层次结构。另一个例子是手动编写SQL查询以实现分页的痛苦。
使用ORM的可能例外是,如果该应用程序是一个ORM框架,设计用于应用专门的业务逻辑抽象,并且设计用于在多个项目上重用。然而,即使是这样,通过使用这些抽象增强现有的ORM,您也可以更快地获得采用。
不要让你的高级团队成员的经验把你拖向计算机科学发展的相反方向。我已经在专业上发展了23年,其中一个不变的因素是老派对新事物的蔑视。ORM对SQL的作用就像C语言对汇编的作用一样,你可以打赌,C++和C#的等价物正在发展中。一行新学校代码等于20行旧学校代码。
我认为有很多充分的理由不使用ORM。首先,我是一名.NET开发人员,我喜欢坚持优秀的.NET框架已经为我提供的内容。它可以完成我可能需要的一切。通过这样做,你可以使用更标准的方法,因此,未来从事同一项目的任何其他开发人员都有更好的机会获得现有的数据并使用它运行。微软已经提供了足够的数据访问功能,没有理由放弃它们。
我已经做了10年的专业开发人员,领导了多个非常成功的百万美元以上的项目,我从来没有写过一个需要切换到任何数据库的应用程序。你为什么希望客户这样做?仔细计划,根据需要选择合适的数据库,并坚持使用。就我个人而言,SQL Server可以做我需要做的任何事情。它很简单,而且效果很好。甚至还有一个免费版本支持高达10GB的数据。哦,而且它与.NET.配合得非常好
我最近不得不开始做几个使用ORM作为数据层的项目。我觉得这很糟糕,而且我不得不毫无理由地学习如何使用一些额外的东西。在极为罕见的情况下,客户确实需要更改数据库,与我与ORM提供商打交道相比,我本可以在更短的时间内轻松地重新设计整个数据层。
老实说,我认为ORM有一个真正的用途:如果你正在构建一个像SAP这样的应用程序,它确实需要在多个数据库上运行的能力。否则,作为一个解决方案提供商,我会告诉我的客户,这个应用程序是为在这个数据库上运行而设计的,它就是这样。在10年和无数应用程序之后,这再次成为问题。
否则,我认为ORM是为那些不懂"少即是多"的开发人员准备的,他们认为在应用程序中使用的第三方工具越酷,他们的应用程序就会越好。
当您需要更新50000000条记录时。设置一面旗帜或其他什么。
请尝试在不调用存储过程或本机SQL命令的情况下使用ORM执行此操作。。
更新1:同时尝试检索一个只包含几个字段的记录。(当你有一张非常"宽"的桌子时)。或者标量结果。ORM在这方面也很差劲。
更新2:看起来EF 5.0测试版承诺批量更新,但这是一个非常热门的消息(2012年1月)
我认为,当你在更大的系统上工作时,也许你可以使用像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)系统。
运行时性能是我能想到的唯一真正的缺点,但我认为这不仅仅是对ORM为您节省的开发/测试等时间的公平权衡。在大多数情况下,您应该能够定位数据瓶颈并更改对象结构以提高效率。
我以前没有使用过Hibernate,但我注意到一些"现成"的ORM解决方案缺乏灵活性。我相信这取决于你使用的是什么以及你需要做什么。
ORM有两个方面令人担忧。首先,它们是由其他人编写的代码,有时是封闭源代码,有时开放源代码,但范围很大。其次,他们复制数据。
第一个问题导致两个问题。你是在依赖外来者的代码。我们都这样做,但这样做的选择不应掉以轻心。如果它不能满足你的需求呢?你什么时候会发现这个?你生活在ORM为你绘制的盒子里。
第二个问题是分两个阶段提交。正在将关系数据库复制到对象模型中。您更改了对象模型,它应该更新数据库。这是一个分两个阶段的提交,并不是最容易调试的事情。
我建议阅读ORM的缺点列表。
http://blogs.tedneward.com/2006/06/26/The+越南+Of+计算机+科学.aspx
就我自己而言,我发现ORM对我编写的大多数应用程序都非常有用!
/Asger
我使用Hibernate的经验是,它的语义很微妙,当出现问题时,很难理解到底出了什么问题。我从一个朋友那里听说,通常从Criteria开始,然后需要更多的灵活性,需要HQL,后来注意到,毕竟需要原始SQL(例如,Hibernate没有union AFAIK)。
还有ORM,人们很容易过度使用现有的映射/模型,这导致有一个对象有很多属性没有初始化。因此,在查询之后,事务内部的Hibernate会进行额外的数据提取,这可能会导致速度减慢。同样令人遗憾的是,hibernate模型对象有时会泄漏到视图体系结构层,然后我们会看到LazyInitializationException。
要使用ORM,人们应该真正理解它。不幸的是,人们很容易就会觉得它很容易,但事实并非如此。
我想重新表述一下我最近听到的一句话。"一个好的ORM就像一个Yeti,每个人都在谈论它,但没有人看到它。"
每当我着手处理ORM时,我通常会发现自己在与该ORM的问题/局限性作斗争。最后,是的,它做了我想做的,它写在那个糟糕的文档中,但我发现自己又失去了一个小时,我永远不会得到。任何使用过nhibernate,然后在postgresql上使用过流利nhibernat的人都会理解我所经历的一切。"这个代码不在我的控制之下"的持续感觉真的很糟糕。
我不会指手画脚,也不会说它们不好,但我开始思考我所提供的只是为了在一个表达式中自动化CRUD。现在,我认为我应该少用ORM,也许可以创建或找到一个至少支持数据库操作的解决方案。但只有我一个人。我相信在这个ORM舞台上有些事情是错误的,但我没有足够的技巧来表达什么不是。
我认为使用ORM仍然是个好主意。尤其是考虑到你所处的情况。从你的帖子来看,你在数据库访问策略方面更有经验,我会提到使用ORM。
#1没有任何争议,因为复制和粘贴查询以及文本中的硬编码没有灵活性,而对于#2,大多数orm将包装原始异常,允许跟踪生成的查询等,所以调试也不是火箭科学。
至于验证,在任何内置验证之上,使用ORM通常也可以更容易地开发验证策略。
编写自己的框架可能很费力,而且往往会遗漏一些内容。
编辑:我想再强调一点。如果你的公司采用ORM战略,这将进一步提高其价值,因为你将制定使用和实施的指导方针和实践,每个人都将进一步提高他们对所选框架的了解,从而减轻你提出的问题之一。此外,当情况出现时,你会学到什么有效,什么无效,最终会节省很多时间和精力。
每个ORM,即使是"好的ORM",都会附带一定数量的假设,这些假设与软件用于在应用层和数据存储之间来回传递数据的底层机制有关。
我发现,对于中等复杂的应用程序,围绕这些假设工作通常比简单地编写更直接的解决方案(例如:查询数据和手动实例化新实体)花费更多的时间。
特别是,一旦您使用了多列键或其他适度复杂的关系,这些关系就不在您下载代码时ORM提供的方便示例的范围内,您很可能会遇到问题。
我承认,对于某些类型的应用程序,特别是那些具有大量数据库表或动态生成的数据库表的应用程序来说,ORM的自动魔术过程可能很有用。
否则,就让ORM见鬼去吧。我现在认为它们基本上只是一种时尚。