编辑:原标题:关于使用ORM的好处的问题.
我想使用ORM进行学习,我尝试使用nhibernate.我正在使用该教程,然后我有一个真正的项目.我可以采用"旧方式"或使用ORM.我不确定我完全理解这个好处.一方面,我可以在代码中创建我的抽象,以便我可以更改我的数据库并且与数据库无关.另一方面,如果我实际更改数据库列,我必须更改所有代码.
为什么没有ORM我没有我的应用程序,更改我的数据库并更改我的代码,而不是更改我的数据库,orm和代码?他们的数据库结构是不是改变了那么多?
我相信有很多好处,因为ORM被很多人使用.我只是不确定我是否已经得到它.
谢谢.
编辑:在教程中,他们有许多文件,用于使ORM工作
http://www.hibernate.org/362.html
在应用程序发生变化的情况下,只是说我有"适当的"抽象层似乎需要做很多额外的工作.因为我是新手,它看起来并不容易维护,而且看起来像是额外的工作,而不是更少.
编辑:这是一个老问题,我一直回到.如果没有使用ORM并且不使用嵌入式SQL且不使用.NET LINQ-to-SQL而正确设计应用程序的示例,我想看到的是没有冒犯.我现在在Java世界,我迷失了如何继续前进.这是一个Web应用程序.没有春天,没有其他世俗的框架.JSP,JSTL,EL,HTML,JavaScript,CSS,Java,Tomcat.希望我没有遗漏任何东西.是的,我知道这是一个老问题.它仍然相关.
为什么,为什么,这个行业如此坚持这个概念的灾难?以前的答案都没有充分解决@ johnny的担忧.它们都是半生不熟的挥手理由,可以很好地避开数据库程序员面临的具体问题.
@TTXI的答案是我在问同一个问题时得到的典型答案:层的分离.那是什么意思?为什么我要分开我的图层?或者,更重要的是,如何创建一个与关系层不同但又应该是该层的规范映射的附加层对我有什么好处呢?
此外,(@ johhny尚未得到回应)这如何保护我们免受变化?如果数据库发生变化,ORM层几乎肯定会效仿.实际上,在对象级别不建模连接表的默认做法会使这更糟糕,因为当表不可避免地增加一些额外的列时,您不仅要向对象模型添加一些额外的字段,而且还要更改其拓扑和强制一堆代码重写!这对变革管理来说是一场灾难,也是一个典型的例子,说明误导的关系观(认为它们代表对象)是如何判断灾难的.如果您只是将关系数据库直接映射到编程语言中的全等概念(想想LINQ-to-SQL,而不是 LINQ-to-EF),那么就不会发生这种情况.
在这个领域最大的未解答的问题 - 房间里的大象 - 是:ORM应该解决什么问题?并且不要说"物体 - 关系阻抗不匹配".那只是另一个挥手的挥手.解释阻塞不匹配的原因,以及为什么它应该是数据库而不是语言数据库.我的解释是,大多数编程语言都倾向于表达和处理关系数据,但这是一个开始消失的历史现实(LINQ-to-SQL是朝这个方向迈出的第一步),而不是一个基本原则以声音架构为基础.
有一个原因是ORM变得如此复杂,包括延迟加载,缓存,令人眼花缭乱的持久性和所有权语义等等.而且有一个原因是,对于键盘所有这些额外的冲击,它们仍然无法有效地解决基本问题诸如"哪一对成员共享多个组?"之类的问题.这种关系模型是在网络和层次模型在这些问题的重压下弯曲的时候构思出来的; 这是一股清新的空气.现在我们似乎都渴望回到我们的旧沙坑里,我们认为我们已经发明了一些新的东西(只要我们抓住了我们的鼻子).
(我完全希望在这个答案上被大幅下调.但是当你这样做时请发表评论.我不介意被告知我错了,只要我知道为什么.)
编辑:谢谢@Chris花时间发表评论.它给了我一些具体要点来解决......(请注意,虽然我经常在下面给@Chris讲话,但我并没有试图让他专门负责;他的回答是我在讨论时一直听到的各种评论的典型.所以我希望他不要把我的批评视为个人的冒犯;他们的意图并非如此,我真的很感激他所采取的回应时间.)
首先,让我澄清@Chris的评论和回答中的一些误解.
由于所有显而易见的原因,我不提倡代码中的原始SQL,有些不那么明显(例如,SQL既不是代数也不是微积分,这使得功能分解几乎不可能).
我不提倡单片应用程序设计.一般来说,图层是一件好事.
我不提倡污染具有大量线噪声的对象模型,例如特殊字段,方法和属性.然而,坦率地说,这是一个稻草人,因为域/对象模型仅存在于ORM世界中.现在,我知道LINQ-to-SQL包含了所有这些带有大量噪声的类,但它们只是幕后的管道; 你不编辑那些代码,你通常不应该看它.
现在有人反对这些异议:
可以独立于数据库构建应用程序的断言是没有根据的.总的来说,ORM只是数据层的规范映射(Tables Foo和Bar变成类Foo和Bar,而表FooBar变成类Foo和Bar之间的某种热情).此映射中没有太多的摆动空间,因此对数据模型的任何更改几乎肯定需要对对象模型进行相应的更改.在我看来,这是一件好事,因为与相应的数据库模型完全不同的对象只不过是所有相关人员的额外维护问题.
一旦ORMs产生数据模型独立性的幻觉被抛弃,所有关于直接耦合到数据模型的邪恶的抗议都没有实际意义.但我想进一步追求这一点,而不是简单地解雇它.耦合是系统设计的基本特征.在某些时候,必须做出决定和假设.您无法使用单个"Things"表对所有内容进行编程.您必须确定您的域包含某些特定概念,然后创建尊重这些概念的模式和代码,将它们视为一等公民,对其进行硬编码.应用程序应该独立于数据库的想法是错误的.数据库是(或应该)是企业知识的最纯粹的代表(我知道情况并非总是如此,我将在稍后讨论).耦合到这种表示应该提供最强的弹性保证,因为这样的数据模型只会在业务本身经历一些内在变化时发生变化.简而言之,耦合到精心设计的数据库模式是一件非常好的事情.
分层本身并不是目的.这很好,因为它实现了一些特定的目标.前面的几点表明,ORM所做的方式在数据库和应用程序之间进行分层既不是有效也不是实现弹性变化的真正目标所必需的.这是通过良好的数据库设计实现的.
@Chris声称让数据库决定阻碍OO设计的事情.这是真的,但只有OO设计是知识建模的最佳方式才有意义.OODBMS在市场上几乎完全失败,暗示事实并非如此.具有谓词逻辑基础的关系模型具有与OO设计相同的表达能力,而不会产生OO模型的图论理论复杂性.
@Chris对关系模型的反对,理由是它无法解决今天的问题(因此NoSQL运动)完全不合适.NoSQL意味着"没有SQL",而不是"没有关系模型".不幸的是,即便是NoSQL运动的支持者在这方面似乎也毫无头绪.SQL有很深的缺陷,其中很多都可以追溯到它与关系模型的彻底背离.要说我们应该放弃关系模型,因为SQL糟透了是一个相当明显的案例,即将婴儿扔出洗澡水.
若未使用ORM并没有增加两倍构建应用程序的工作.这是一个荒谬的说法,甚至@Chris似乎也对其进行了后门打开,并对codegen替代方案进行了讽刺.诸如LINQ-to-SQL的sqlmetal之类的Codegen工具对于那些不熟悉教条的人来说是完美的解决方案,因为应用程序的数据模型绝对必须与数据库的数据模型不同.
我自己在ORM方面的经验是,他们在教程中工作得很好,并在现实世界中造成无尽的痛苦和挫折.由于LINQ-to-SQL修复了许多首先激发ORM的问题,我认为没有理由让自己经历这种折磨.
仍然存在一个主要问题:当前的SQL数据库不会对物理层和逻辑层的分离提供任何有意义的控制.从表到磁盘上的内容的映射基本上是固定的,完全在SQL DBMS的控制之下.这不是关系模型计划的一部分,它明确地将两者分开,并允许定义可以以与逻辑模型建议的完全不同的结构存储在磁盘上的数据的一致逻辑表示.例如,出于性能原因,系统(或dba)可以自由地进行物理非规范化 - 高度标准化的逻辑模型.由于SQL引擎不允许这种关注点的分离,因此通过纯粹的必要性来对逻辑模型进行非规范化或以其他方式折磨是很常见的.因此,逻辑模型并不总是完全正确,因此无法完全实现使用数据库作为最纯粹的知识表示的理想.然而,在实践中,设计师通常坚持从数据库到域模型的规范映射,因为其他任何东西都太难以维护.
在我与NHibernate的经验,这是一个有点像Visual Basic:它使简单的问题真的很容易,但它也使什么比这更难真的很难,甚至完全不可能.
基本思想是ORM避免编写持久性代码.这些代码中存在大量重复,因此将代码设置为通用代码非常诱人,而不是特定于特定业务层,并在项目中重复使用它.到现在为止还挺好.对于简单的对象层次结构和业务需求,这实际上非常有效.如果您的数据库发生了变化,是的,您必须更改ORM映射文件,但这通常非常简单,您只需在一个地方进行更改 - 比更改访问数据库的代码要容易得多.
问题是随着您的数据库和需求变得越来越复杂,ORM发现它越来越难以跟上.因此ORM变得越来越复杂.它也需要快捷方式,做一些效率低下的事情,因为它并不够聪明,无法确定如何在所有情况下有效地做到这一点.更重要的是,因为整个想法是它透明地工作,你经常看不到这些性能问题,直到它们变得足以影响用户体验.一个相关的问题是bug很难找到,因为你只是不知道ORM内部发生了什么,除非你调试它.(是的,我不得不单步执行NHibernate代码,这不是野餐!)
因此,您开始绕过ORM以获取某些内容并直接使用SQL.当然,你就必须让这与代码代码工作不使用ORM,这是更多的工作.您最终编写代码来手动加载和保存一些对象,并以某种方式将其用于ORM代码.最终你开始怀疑ORM是否为你创造了更多的工作而不是节省 - 更不用说性能和漏洞问题了.
因此,如果你正在编写一个非常简单的应用程序,那么你在教程中找到的那种,ORM就能做得很好.如果它比那更复杂,那么我认为这不值得.当然,对于简单的应用,节省的绝对时间量也会很小.我的结论:只是不要打扰ORM.ORM是通往黑暗面的道路.
在阅读本文之前,我经常想知道是否有其他人真的很难理解ORM工具对项目的影响.@Evgeny,@ Marcelo Cantos和@Jimmy B让这个休息.
简而言之,围绕ORM工具的大多数问题他们都已经死了.只有一对他们要么没有覆盖,要么没有足够的覆盖.
首先,使用ORM并不意味着代码更少.它可能意味着更少的SQL,但它肯定并不意味着更少的代码.沿着这些方向,工具生成的代码可能是错误的.更糟糕的是,补偿糟糕的生成代码是一种令人沮丧的行为.
其次,ORM工具并不意味着您不必了解SQL.换句话说,你必须知道SQL是一个有效的程序员(有像嵌入式人一样的例外).从性能或资源角度来看,这些工具发出的查询(包括类型和数量)都不够好.如果您已经知道SQL,为什么要束缚自己?
第三,ORM工具不会节省时间.您将花费尽可能多的时间(如果不是更多)将您选择的ORM工具投入提交,以处理任何体面大小的应用程序.为了增加对伤害的侮辱,当你完成后,你会发现查询的质量通常比你自己做的更差.点是ORM =花在项目上的时间更多,结果更差.
第四,DBMS独立性通常是浪费时间.大多数应用程序将在其生命周期中使用一个DBMS; 无论是Oracle,SQL服务器,MySql等等.应用程序将更好,它能够利用DBMS提供的功能.与DBMS无关,意味着您必须将自己限制为低于标准的查询.
第五,并非一切都必须成为一个对象.这是一个值得注意的重要事项.我们经常被要求在页面上显示一组特定的数据.这通常意味着从两个或多个表中连接数据.你的应用程序是否必须创建并实例化所有这些对象才能显示一些数据?或者你最好只是执行查询并以您选择的格式直接将数据发送到屏幕/浏览器?
即使是最简单的事情,ORM也会增加很多开销.大多数ORM会生成多个SQL查询,甚至可以在表上执行简单的UPDATE.
第六,也是我心中最重要的问题:ORM会降低您的安全性.当然你可以将ORM与s'procs一起使用; 但大多数人没有.我看到的几乎所有使用ORM的应用程序都暴露了数据库,如果网站被破解,整个数据库很容易被杀死或被盗.ORM工具动态生成SQL.这意味着他们需要直接访问表.这意味着,如果您的应用受到攻击,黑客将拥有直接表访问权限.这意味着您已从应用程序中有效地删除了至少一层安全性.
我意识到这个问题是在不久前发布的,但我想知道和约翰尼一样.我已经看到Hibernate被智能人员用于几个大型项目,并且无论如何,这都是一场彻底的灾难.根据我的经验,大多数企业应用程序中最复杂且影响最大的区域是业务层和数据库层.这是我们添加数据访问层以尝试将数据库交互封装到可管理块中的部分原因.
我看到使用ORM的最大论点是它们"减少手写代码"并提供一个将业务逻辑与数据访问分开的抽象层.我断言,除非在非常简单的情况下,这些都不是真的.
为了使Hibernate(和大多数其他ORM工具)工作,我们要么创建一个hibernate映射文件来记录所有数据库和对象的交互,要么我们使用注释来记录相同的关系.在一个案例中,我们将代码移动到一个更难测试的xml配置文件,但同样复杂.另一方面,我们分发了如何在整个域模型中与数据库进行交互的逻辑.关键是,虽然我们编写了较少的实际"代码",但将代码移动到配置文件或注释!="less code".它只是将代码中的复杂性从我们可以直接控制并减轻它的位置转移到控制较少的第三方工具.
应该将业务/域层与数据库层分开的ORM抽象层往往具有更微妙的效果来抵消这种"分离".您是否看过ORM层以何种方式影响对象模型和/或数据库设计的项目数量?要使用糟糕的物理类比,假设您的业务层,ORM层和数据库层都具有质量.仅仅存在另一个之间的ORM层趋向于施加改变和扭曲其他层的力.您是否必须引入一个不太适合您的业务模型的主键对象,因为ORM层需要它?您是否必须调整数据库结构以适应特别复杂的对象图模型,否则ORM工具无法处理它?从极端看,ORM层的存在可以扭曲数据库交互应该如何工作的整个视角.它可以代替处理持久对象图的服务层,而不是为每个域对象创建单独的数据访问层对象,就像它们独立存在一样.我已经在不同程度上看到了所有这些情景.也许它对ORM工具集缺乏经验.也许这是一个糟糕的数据库结构.我对此表示怀疑.我所看到的一切都表明ORM解决方案不够充分.
如果您接受我的断言数据访问层是复杂性,非常容易出现性能瓶颈,为什么我应该考虑添加一个不能实现更少代码和分离的目标的工具,同时又会对其产生负面影响我申请的其他层的结构?
我对@Marcelo Cantos的答案作出了彻底的回应,但是我将总结使用ORM的主要好处.
ORM非常适合这两种总体设计模式.对于正确的面向对象设计,您将使用分层和多态对象来表示数据在应用程序中的流动方式.通过良好的设计,您将经常争取POCO对象(普通的旧C/C#对象,我已经看到了这个单词的其他定义),因为如果我有一个具有List的Person,我就应该拥有它.我不应该有一个DataTable的人和一个DataTable的地址,我不知何故强迫我的应用程序.除此之外,我不需要将大量数据库特定逻辑绑定到我的对象,为什么我的人的FirstName字段需要具有类似的东西[ColumnName("First_Name")] [Length(255)] [DataType(Types.Nvarchar)]
或任何其他各种各样的疯狂属性或代码来定义强制进入的数据库的数量我的域名设计?
当您不再为应用程序中的每个对象编写Select,Insert,Update和Delete语句以将其保存到数据库时,写入的代码行数会大幅减少.这使您只需要编写具有某些意义的查询.此外,许多ORM(如NHibernate)将包含一种在SQL之上分层的语言,这种语言更多地定义为与之交互,并且可以在语法上更少地填充.
最充分展示的时间是考虑一个具有UserTable的应用程序,该UserTable链接到每个对象,并且由于某种原因,您必须更改主键名称或类型.此时,您可能需要更改数据库中的每个存储过程,使用正确实现的ORM解决方案,您只需要更改一些配置映射(或者可能没有),并且已完成.
使用ORM工具的基本好处是便于在多层应用程序中将业务逻辑与数据访问分离.如果您可以成功构建一个响应数据库更改的数据访问层(通过更改映射),那么在进行更改时,您需要更少的整体代码.
层的分离通常是3层或n层应用程序的目标,ORM是一种很好的方法.