为什么我们需要实体对象?

时间:2008-08-20 19:37:54

标签: sql database orm entities

41 个答案:

答案 0 :(得分:59)

我认为这取决于应用程序的“逻辑”有多复杂,以及您实现它的位置。如果您的所有逻辑都在存储过程中,并且您的所有应用程序都在调用这些过程并显示结果,那么开发实体对象确实是浪费时间。但是对于一个应用程序,其中对象彼此之间具有丰富的交互,并且数据库只是一个持久性机制,那么拥有这些对象是有价值的。

所以,我会说没有一个适合所有人的答案。开发人员确实需要意识到,有时候,尝试过于OO会导致更多问题而不是解决问题。

答案 1 :(得分:27)

理论认为,高度凝聚力,松散耦合的实施是前进的方向。

所以我想你正在质疑这种方法,即分离问题。

我的aspx.cs文件是否应该与数据库交互,调用sproc并理解IDataReader?

在团队环境中,特别是在技术人员处理应用程序的aspx部分的情况下,我不需要这些人能够“触摸”这些东西。

将我的域名与数据库分开可以保护我免受数据库中的结构变化的影响,这当然是件好事吗?确保数据库功能绝对重要,所以让那些最优秀的人在一个地方处理这些东西,对系统其他部分的影响尽可能小。

除非我误解了您的方法,否则数据库中的一个结构更改可能会对应用程序的表面产生很大的影响。我看到这种关注点的分离使我和我的团队能够最大限度地减少这种情况。此外,团队的任何新成员都应该更好地理解这种方法。

此外,您的方法似乎主张应用程序的业务逻辑驻留在您的数据库中?这对我来说是错的,SQL非常擅长查询数据,而不是imho,表达业务逻辑。

虽然有趣的想法,虽然它感觉asp中的SQL只有一步之遥,这是我糟糕的非结构化asp时代,让我感到害怕。

答案 2 :(得分:25)

一个原因 - 将您的域模型与数据库模型分开。

我所做的是使用测试驱动开发,所以我首先编写我的UI和模型层,并且模拟数据层,因此UI和模型是围绕特定于域的对象构建的,然后我将这些对象映射到任何技术我使用数据层。让数据库结构决定应用程序的设计是个坏主意。在可能的情况下,首先编写应用程序,然后让它影响数据库的结构,而不是相反。

答案 3 :(得分:22)

对我来说,归结为我不希望我的应用程序关注数据的存储方式。我可能会因为这样说而被打耳光...但你的应用程序不是你的数据,数据是应用程序的工件。我希望我的应用程序能够根据客户,订单和项目进行思考,而不是像DataSet,DataTables和DataRows这样的技术...因为谁知道这些技术会持续多久。

我同意总是存在一定量的耦合,但我更喜欢耦合向上而不是向下。我可以更容易地调整树的四肢和树叶,而不是改变它的树干。

我倾向于保留用于报告的垃圾邮件,因为查询确实比应用程序通用数据访问更加糟糕。

我也倾向于在早期的情况下考虑适当的单元测试,就像没有持久的一列可能不是问题。

答案 4 :(得分:16)

埃里克 你死了。对于任何真正可扩展/易于维护/强大的应用程序,唯一真正的答案是免除所有垃圾并坚持基础。

我的职业生涯遵循了类似的轨迹,得出了相同的结论。当然,我们被认为是异教徒,看起来很有趣。但我的东西运作良好。

每一行代码都应该怀疑。

答案 5 :(得分:11)

我想回答一个类似于你提议的例子。

在我公司,我必须为产品构建一个简单的CRUD部分,我构建所有实体和一个单独的DAL。后来另一个开发人员不得不改变一个相关的表,他甚至重命名了几个字段。我必须更改以更新表单的唯一文件是该表的DAL。

我认为实体为项目带来的是:

Ortogonality:一个层中的更改可能不会影响其他层(当然,如果您对数据库做出巨大更改,它会波及所有层,但大多数小更改都不会)。

可测试性:您无需触摸数据库即可测试逻辑。这样可以提高测试的性能(允许您更频繁地运行它们)。

关注点分离:在一个大产品中,您可以将数据库分配给DBA,他可以优化地狱。将模型分配给具有设计所需知识的业务专家。将个别表单分配给在webforms等方面更有经验的开发人员。

最后,我想补充一点,大多数ORM映射器都支持存储过程,因为这就是你正在使用的。

干杯。

答案 6 :(得分:8)

我认为你可能在这个话题上“咬得比你能咀嚼的多”。当他称之为“Vietnam of Computer Science”时,特德·纽瓦德并不轻浮。

我绝对可以向你保证的一点是,它会改变任何人的观点,正如在无数其他博客,论坛,播客等上经常证明的那样。

对一个有争议的话题进行公开的讨论和辩论当然是可以的,只是这一次已经做了很多次,以至于双方都同意不同意并且继续编写软件。

如果你想进一步阅读双方,请参阅Ted博客上的文章,Ayende Rahein,Jimmy Nilson,Scott Bellware,Alt.Net,Stephen Forte,Eric Evans等。

答案 7 :(得分:7)

@Dan,对不起,那不是我想要的那种东西。我知道这个理论。你的陈述“是一个非常糟糕的主意”并没有一个真实的例子支持。我们正在努力在更短的时间内开发软件,减少人员,减少错误,并且我们希望能够轻松地进行更改。根据我的经验,您的多层模型在所有上述类别中都是否定的。特别是关于使数据模型成为你做的最后一件事。从第1天起,物理数据模型必须是一个重要的考虑因素。

答案 8 :(得分:4)

我发现你的问题非常有趣。
通常我需要实体对象来封装应用程序的业务逻辑。将这种逻辑推入数据层将是非常复杂和不充分的 你会做些什么来避免这些实体对象?你有什么解决方案?

答案 9 :(得分:4)

非常有趣的问题。老实说,我无法证明为什么实体是好的。但我可以分享我的观点,为什么我喜欢它们。代码如

void exportOrder(Order order, String fileName){...};

不关心订单来自哪里 - 来自DB,来自Web请求,来自单元测试等。它使得此方法更明确地声明它究竟需要什么,而不是采用DataRow并记录它期望具有哪些列以及哪些列他们应该是什么类型。如果您以某种方式将其实现为存储过程,则同样适用 - 您仍然需要将记录ID推送到它,而不必在DB中存在。

此方法的实现将基于订单抽象,而不是基于它在DB中的呈现方式。我实施的大多数此类操作实际上并不依赖于这些数据的存储方式。我确实理解一些操作需要与DB结构耦合以实现性能和可伸缩性目的,仅根据我的经验,它们并没有太多。根据我的经验,通常知道Person有.getFirstName()返回String,返回地址的.getAddress(),地址有.getZipCode()等等 - 并且不关心调用哪些表来存储该数据

如果你必须处理你所描述的问题,比如额外的列断点报告性能,那么对于你的任务,DB是一个关键部分,你确实应该尽可能接近它。虽然实体可以提供一些方便的抽象,但它们也可以隐藏一些重要的细节。

可扩展性在这里很有意义 - 大多数需要巨大可扩展性的网站(如facebook,livejournal,flickr)倾向于使用DB-ascetic方法,当尽可能少地使用DB并通过缓存解决可伸缩性问题时,尤其是RAM使用情况。 http://highscalability.com/有一些有趣的文章。

答案 10 :(得分:4)

我们还应该谈论实体究竟是什么。 当我阅读这篇讨论时,我得到的印象是,这里的大多数人都在关注Anemic Domain Model意义上的实体。 很多人都在考虑将贫血领域模型作为反模式!

富域模型有价值。这就是Domain Driven Design的全部意义所在。 我个人认为面向对象是一种克服复杂性的方法。这不仅意味着技术复杂性(如数据访问,ui绑定,安全......),还意味着业务领域的复杂性

如果我们可以应用面向对象技术来分析,建模,设计并实施我们的业务问题,这对于非平凡应用程序的可维护性和可扩展性来说是一个巨大的优势!

您的实体和表格之间存在差异。实体应该代表您的模型,表格只代表模型的数据方面!

数据确实比应用程序更长久,但考虑来自this quoteDavid Laribee:模型永远是......数据是一个快乐的副作用。

关于此主题的更多链接:

答案 11 :(得分:4)

除了抽象和松散耦合之外,实体对象还有其他充分的理由。我最喜欢的一件事是使用DataReader或DataTable无法获得的强类型。另一个原因是,如果做得好,正确的实体类可以通过使用特定领域术语的第一类构造使代码更具可维护性,任何查看代码的人都可能理解而不是使用其中包含字段名称的一堆字符串用于索引DataRow。存储过程实际上与ORM的使用正交,因为许多映射框架使您能够映射到sprocs。

我不认为sprocs + datareaders可以替代好的ORM。使用存储过程,您仍然受到过程类型签名的约束和紧密耦合,该签名使用与调用代码不同的类型系统。可以修改存储过程以修改其他选项和架构更改。在架构可能发生变化的情况下,存储过程的替代方法是使用视图 - 您可以将对象映射到视图,然后在更改它们时将视图重新映射到基础表。

如果您的经验主要包括Java EE和CSLA,我可以理解您对ORM的厌恶。您可能希望了解LINQ to SQL,它是一个非常轻量级的框架,主要是与数据库表的一对一映射,但通常只需要很小的扩展即可成为完整的业务对象。 LINQ to SQL还可以将输入和输出对象映射到存储过程的参数和结果。

ADO.NET实体框架的另一个优点是,您可以将数据库表视为彼此继承的实体类,或者将多个表中的列聚合到单个实体中。如果需要更改架构,可以在不更改实际应用程序代码的情况下更改从概念模型到存储架构的映射。同样,这里可以使用存储过程。

我认为企业中的更多IT项目由于代码不可维护或开发人员的工作效率低(可能发生在sproc-writing和app-writing之间的上下文切换)而不是应用程序的可伸缩性问题而失败。 p>

答案 12 :(得分:4)

实体对象可以促进应用层的缓存。祝你好运缓存datareader。

答案 13 :(得分:3)

你可能会发现有关comp.object的帖子this

我并不是声称同意或不同意,但这很有趣并且(我认为)与这个主题相关。

答案 14 :(得分:3)

问题:如果所有业务逻辑都被困在数据库中,如何处理断开连接的应用程序?

在我感兴趣的企业应用程序类型中,我们必须处理多个站点,其中一些站点必须能够在断开状态下运行。
如果您的业务逻辑封装在一个很容易合并到各种应用程序类型的Domain层中,那么我可以构建知道业务规则的应用程序,并且必要时可以将其编译为dll。在当地应用它们。

在将数据库保存在数据库的存储过程中时,您必须坚持使用一种需要数据库永久视线的应用程序。

适用于某类环境,但它无法覆盖整个企业应用程序

答案 15 :(得分:3)

我还要添加Dan's answer,将两个模型分开可以使您的应用程序在不同的数据库服务器甚至数据库模型上运行。

答案 16 :(得分:3)

如果您需要通过负载平衡多个Web服务器来扩展应用程序,该怎么办?您可以在所有Web服务器上安装完整的应用程序,但更好的解决方案是让Web服务器与应用程序服务器通信。

但如果没有任何实体对象,他们就不会有太多可谈的内容。

我并不是说如果它是一个简单的,内部的,短暂的生命应用程序,你不应该写monoliths。但是一旦它变得中等复杂,或者它应该持续很长时间,你真的需要考虑一个好的设计。

这样可以节省维护时间。

通过从表示逻辑和数据访问中分离应用程序逻辑,并通过在它们之间传递DTO,您可以将它们分离。允许他们独立改变。

答案 17 :(得分:2)

埃里克,

没有人阻止您选择您希望的框架/方法。如果你打算采用“数据驱动/存储过程驱动的”路径,那么一定要去吧!特别是如果确实如此,真的可以帮助您按规格和准时交付应用程序。

需要注意的是(问题的另一面),您的所有业务规则都应该存储在存储过程中,而您的应用程序只不过是瘦客户端。

话虽如此,如果您在OOP中执行申请,则适用相同的规则:保持一致。遵循OOP的原则, 包括创建实体对象来代表您的域模型。

这里唯一真正的规则是一致性这个词。没有人阻止你以数据库为中心。没有人阻止你做旧式结构(又称功能/程序)程序。好吧,没有人阻止任何人做COBOL风格的代码。但是,如果应用程序希望获得任何程度的成功,那么一旦应用程序必须非常非常一致。

答案 18 :(得分:2)

我想提出另一个角度来解决OO和RDB之间的距离问题:历史。

任何软件都有一种现实模型,在某种程度上是对现实的抽象。没有计算机程序可以捕捉到现实的所有复杂性,而程序只是为了解决现实中的一系列问题而编写的。因此,任何软件模型都是现实的减少。有时,软件模型迫使现实减少自己。就像你希望汽车租赁公司为你预留任何汽车一样,只要它是蓝色的并且有合金,但操作员无法遵守,因为你的要求不适合电脑。

RDB源于将信息放入表格的传统,称为会计。会计是在纸上完成的,然后是打卡,然后是计算机。但会计已经减少了现实。会计迫使人们长期遵循其制度,已成为公认的现实。这就是为什么计算机软件用于会计相对容易,会计已经有了它的信息模型,早在计算机出现之前。

鉴于良好会计系统的重要性以及您从任何业务经理那里获得的认可,这些系统已经变得非常先进。数据库基础现在已经非常可靠,没有人对将重要数据保存在如此值得信赖的东西中犹豫不决。

我猜想,当人们发现现实的其他方面比会计更难建模(已经是模型)时,OO必定会出现。 OO已成为一个非常成功的想法,但OO数据的持久性相对不发达。 RDB / Accounting很容易获胜,但OO是一个更大的领域(基本上所有都不是会计)。

我们很多人都想使用OO但我们仍然希望安全存储我们的数据。比尊重的会计系统更能比存储我们的数据更安全吗?这是一个诱人的前景,但我们都陷入了同样的陷阱。与RDB行业的大量努力相比,很少有人考虑过OO持久性,而RDB行业已经从会计的传统和地位中受益。

Prevayler和db4o是一些建议,我敢肯定还有其他一些我没有听说过的,但似乎没有一个人能够获得一半的新闻,比如冬眠。

对于多用户应用程序,尤其是Web应用程序,甚至似乎都没有认真地将对象存储在好的旧文件中。

在我日常努力缩小OO和RDB之间的鸿沟时,我尽可能使用OO,但尽量将继承保持在最低限度。我不经常使用SP。我只会在看起来像会计的方面使用高级查询。

当鸿沟关闭时,我会很高兴地被贬低。我认为当Oracle推出像“Oracle Object Instance Base”这样的东西时,解决方案就会出现。要真正流行起来,它必须有一个令人放心的名字。

答案 19 :(得分:2)

@jdecuyper,我经常重复的一句格言是“如果你的业务逻辑不在你的数据库中,那只是一个建议”。我认为保罗·尼尔森在他的一本书中说过。应用程序层和UI来来去去,但数据通常会存在很长时间。

如何避免实体对象?存储过程大多数。我还自由地承认,无论您是否愿意,业务逻辑都会遍及应用程序中的所有层。一定程度的耦合是固有的,不可避免的。

答案 20 :(得分:2)

我真的不确定你认为“企业应用程序”。但我得到的印象是,您将其定义为内部应用程序,其中RDBMS将被设置为一体,系统不必与任何其他系统(无论是内部还是外部)互操作。

但是如果你有一个包含100个表的数据库,相当于每个表的4个存储过程,如果只是基本的CRUD操作,那就是需要维护的400个存储过程并且不是强类型的,因此很容易出现拼写错误,也可以单位测试。当你获得一位新的CTO谁是开源福音传播者并希望将RDBMS从SQL Server更改为MySql时会发生什么?

今天的许多软件,无论是企业应用程序还是产品都在使用SOA,并且对于公开Web服务有一些要求,至少我所参与的软件是这样做的。 使用您的方法,您最终会暴露出Serialized DataTable或DataRows。现在,如果保证客户端是.NET并且在内部网络上,则可以认为这是可以接受的。但是当客户端未知时,您应该努力设计一个直观的API,在大多数情况下,您不希望暴露完整数据库架构。 我当然不想向Java开发人员解释DataTable是什么以及如何使用它。还有Bandwith和有效载荷大小以及序列化DataTables的考虑,DataSet非常重。

没有软件设计的灵丹妙药,它实际上取决于优先级所在,对我来说,它是单元可测试代码和松散耦合的组件,可以很容易地被任何客户端使用。

只是我的2美分

答案 21 :(得分:2)

我最近一直在考虑同样的事情;我有一段时间是CSLA的重度用户,我喜欢说“所有业务逻辑(或至少尽可能多的合理可能)封装在业务实体中”的纯洁性。“

我已经看到,在数据库设计与处理数据的方式不同的情况下,业务实体模型提供了很多价值,很多商业软件就是这种情况。

例如,“客户”的想法可能包括客户表中的主记录,结合客户所下的所有订单,以及所有客户的员工及其联系信息,以及可以从查找表中确定客户及其子项的属性。从开发的角度来看,能够作为单个实体与客户合作是非常好的,因为从业务角度来看,Customer的概念包含所有这些内容,并且可能会或可能不会在数据库中强制执行关系。 / p>

虽然我感谢引用“如果您的业务规则不在您的数据库中,这只是一个建议”,我也相信您不应该设计数据库来强制执行业务规则,您应该将其设计为高效,快速和规范化。

如上所述,正如其他人所说,没有“完美设计”,工具必须适合这项工作。但是,使用业务实体可以真正帮助维护和提高工作效率,因为您知道在哪里修改业务逻辑,而对象可以直观地为现实世界的概念建模。

答案 22 :(得分:1)

目前不是很多时间,但只是在我的头顶......

实体模型允许您为数据库(和其他可能的系统)提供一致的接口,甚至超出存储过程接口的范围。通过使用企业范围的业务模型,您可以确保所有应用程序始终如一地影响数据,这是非常重要的事情。否则你最终会得到糟糕的数据,这只是一种邪恶的行为。

如果您只有一个应用程序,那么您实际上没有“企业”系统,无论该应用程序或您的数据有多大。在这种情况下,您可以使用类似于您所谈论的方法。如果您决定将来扩展系统,请注意所需的工作。

以下是您应该记住的一些事项(IMO):

  1. 生成的SQL代码很糟糕 (例外情况)。对不起 知道很多人都这么认为 这是一个巨大的节省时间,但我已经 从来没有找到一个可以的系统 生成更有效的代码 我能写什么,往往是 代码简直太可怕了。您 也往往最终产生吨 从未使用过的SQL代码。 这里的例外非常简单 模式,比如查找表。 很多人都被贬低了 不过。
  2. 实体<>表(甚至必然是逻辑数据模型实体)。数据模型通常具有应尽可能与数据库紧密相关的数据规则,其中可以包括关于表行彼此之间的关系的规则,或者对于声明性RI而言过于复杂的其他类似规则。这些应该在存储过程中处理。如果所有存储过程都是简单的CRUD过程,则不能这样做。最重要的是,CRUD模型通常会产生性能问题,因为它不会最小化网络到数据库的往返行程。这通常是企业应用程序中最大的瓶颈。

答案 23 :(得分:1)

有时,您的应用程序和数据层并没有紧密耦合。例如,您可能有电话帐单申请。您稍后会创建一个单独的应用程序来监控电话的使用情况,以便a)更好地向您发布广告b)优化您的电话计划。

这些应用程序有不同的关注点和数据要求(即使数据来自同一个数据库),它们也会驱动不同的设计。如果让数据库驱动代码,你的代码库可能会导致绝对混乱(在任一应用程序中)和维护的噩梦。

答案 24 :(得分:1)

具有与数据存储逻辑分离的域逻辑的应用程序适用于任何类型的数据源(数据库或其他)或UI(Web或Windows(或linux等))应用程序。

你几乎陷入了数据库,如果你的公司对你当前使用的数据库系统感到满意,那也不错。但是,由于数据库随着时间的推移而发展,可能会有一个新的数据库系统,这个系统非常简洁,是贵公司想要使用的。如果他们想要切换到数据访问的Web服务方法(如某些时候的服务导向架构),该怎么办?您可能必须在整个地方移植存储过程。

域逻辑也抽象出UI,这在具有不断发展的UI的大型复杂系统中更为重要(特别是当他们不断搜索更多客户时)。

此外,虽然我同意存储过程与域逻辑的问题没有明确的答案。我在域逻辑阵营(我认为他们随着时间的推移而获胜),因为我相信精心设计的存储过程比精心设计的域逻辑更难维护。但这是另一场辩论

答案 25 :(得分:0)

每种方法都有优势。必须根据具体情况判断它们对特定问题的适用性。

我全心全意地相信实体 - (因而面向对象)设计简化了其他复杂的业务逻辑,正如其他人所指出的那样。但在我看来,基于实体的设计的最大优势是模块化,通过明确定义的输入和输出,这更容易实现外部数据库和面向对象的模型。我将在下面详细说明。

我是Linux用户。 Unix理念中的一点是开发人员应该编写程序来处理文本流,因为这是一个通用的接口"。 Linux也是如此,因为它非常以文本为中心。您可以将不相关的流程链接在一起以实现新的功能,例如grep ^col /var/log/bim-sync | sed 's/.*alt:\([0-9]\{1,\}\).*/\1/g | xargs -I replstr bim-transcoder replstr。这些程序完全彼此无知,但可以很容易地结合在一起,以实现新的目的。这是可能的原因是因为你(" glue"的作者)知道每个过程的输入和输出格式。

现在,我不相信文本流在任何地方都适用。文本流很常见,但不是通用的。我的发展理念是“编写具有明确定义的输入和输出的程序”。我在这里讨论的输入/输出不一定是标准的输入/输出,也不一定是文本的 - 它可以是命令行程序的参数,通过网络套接字发送的原始字节,内存之间传递的内存数据结构代码层等等。根据你们Input-Process-Output"黑盒子"允许您像Unix中的命令行实用程序一样编写应用程序 - 独立使用一层粘合剂将它们连接在一起。

例如,假设您正在为澳大利亚新南威尔士Births, Deaths and Marriages编写软件。当孩子的出生登记进入时,操作员输入详细信息,扫描签名的表格并点击提交按钮。点击提交按钮会发出RegisterBirth命令。该软件验证命令的详细信息(出生日期和时间,医院等),并发出BirthRegistered事件。这个事件包括许多关于分娩的细节,例如分娩医生,无论是自然分娩还是剖腹产,如果是剖腹产,是否是紧急情况,亲生父母是谁等等很多不同的代码可以插入"这个事件。例如,一段代码可以发出简单的insert into person... SQL语句,而另一段代码可以发出一系列Neo4j cypher命令来存储新生婴儿以及与其亲生父母的关系。第二段代码将允许极快地查询分层的"系列树"数据。无论您是否使用adjacency lists or nested sets,SQL数据库中的此类查询都会更慢(也更复杂)。还有一段代码可以更新当月紧急剖腹产数量的统计数据,由于历史原因存储在XML文件中。

模块化不会因抽象持久性机制而停止。例如,您可以编写FastCGI"胶水层"网络启用您的应用程序:"输入"您的Web服务器接受HTTP请求,该服务器会发出"输出" FastCGI请求您的"胶水层"。你的FastCGI"胶水层"接受它作为输入并将其转换为适合您的应用程序的输出形式。您的应用程序接受输入命令并发出事件或错误,这些事件或错误可由其他"粘合层" (例如上面给出的SQL和Neo4j示例)。

模块化几乎可以在任何方向上继续。您可以拥有命令行界面或GUI界面。您可以创建一个全面的自动化测试套件。您可以打开您的应用程序,直到第三方编写脚本。这里有很多概念与Domain Driven DesignCommand Query Responsibility SegregationEvent Sourcing有关,这三种相互关联的模式我发现它们非常强大。

当使用基于实体的方法时,有很多相关的架构。例如,杰里里·巴勒莫的Onion Architecture和阿利斯泰尔·科克本的Ports and Adapters(或六角建筑)。所有这些架构的共同点是通过定义的输入和输出实现模块化和抽象,无论这些输入/输出边界是否在单个程序中,或者它们是否跨越多个进程甚至网络。

基于实体的方法提供了模块化和灵活性。但是,这种方法存在缺点,其中三个很重要:

  1. 首先,初期投资很高。这意味着这种方法对于范围较小的项目没有意义。

  2. 其次,您必须编写的胶水代码量会变大。编写胶水代码可能很乏味,但它也可以是有益的。例如,假设您的应用程序与PostgreSQL松散地集成,因为它的存储后端。当公司董事决定该应用程序应该支持Microsoft SQL Server时,如果在到期日之前达到目标并且低于预算,那么它将非常令人满意(并建立团队士气)。

  3. 第三,我的经验告诉我,基于实体的方法可能比简单的SQL解决方案更糟糕,具体取决于实施它的人的专业知识。例如,如果实体优先方法充满了getters和setter,它们只不过是数据库表的内存中表示,那么可以确定问题没有被考虑过。像这样的情况可以理解地让开发人员感到困惑"为什么我们不写SQL?"

  4. 参考文献:

答案 26 :(得分:0)

以适用于大量实际情况的非常通用的方式解决大问题的软件必然会带来性能成本。它需要代码来处理所有这些通用性,并且代码需要时间来运行。

此外,通过抽象层下降总是会发现有些东西花费很少,有些东西花费很多,而这些差异被抽象所隐藏。抽象的隔离给开发人员带来的东西总是会导致开发人员随意引入比必要的更昂贵的操作。

无论对于这个问题还有什么可以说的,从性能的角度来看,从仅仅扩展性能的角度来看,避免因自身数据库的实际情况的额外隔离而导致的双重打击将会在性能上得到回报。

我目前正在花费我的工作时间来完全解决由这些问题引起的性能问题,而且他们是可怕的怪物。

答案 27 :(得分:0)

我最近偶然发现了这个问题。意识到这个问题已经很老了,并且有很多答案,我明白我的回答很多都不会被看到。不过,我想在此发表评论。

我会从三个方面来看这个问题。但在此之前,我必须指出:8个中的8个,来自命令式/ OO设计世界的程序员(C / C ++,JAVA,C#等)不知道如何编写优化的,高效的SQL代码即可。根据我的经验,很少有人能够在应用程序开发 SQL开发方面做得很好。

话虽如此,我想提出三个方面来看待这个问题。

首先:关注的分离不是根据计划,而是根据组织层次结构

坦率地说,有很多种"企业"在这个世界上,每个人都有自己的组织等级,因历史和哲学而异。在我曾经使用的一家公司中,程序员无法修改或开发数据库。他们可以读取和使用数据库API(即SQL Server中的存储过程),但不能直接读取数据库,也不能编写任何查询或存储过程。

任何数据库请求(数据或功能)都必须委托给另一个角色:Data Architect。他/她将是处理数据库的开发和维护的人。 (虽然维护部分应该是DB Admin的工作。)在这样的环境中,存储过程只是消耗品;甚至PROD环境中存储过程的来源也会被加密,程序员不允许看到SP的来源。

但是,在其他一些组织中,程序员希望进行各方面的开发,包括界面,中间件和数据存储。这是大多数情况。

在这两种情况下(尽管第一种情况相当极端但却是真实的),它会影响您查看作者问题的方式。在第一种情况下,我会说作者会同意数据架构师的角色,但组织中的任何非数据库程序员都会非常鄙视。然而,在第二种情况下,由于我之前的免责声明,许多开发人员不知道如何编写好的SQL代码(并且通常也不喜欢处理它),因此选择更简单的方法是很自然的:ORM。

第二:数据库的作用:纯数据存储直到不同的解释,或预定义信息方案的提供者

定义:"数据"是原始,而"信息"被解释。

在许多实际情况中,数据库仅被视为纯数据存储。它可能包含数据逻辑(例如关系数据的完整性),但它不包含业务逻辑(例如,任何应用于数据的公式都不是因为数据的性质,而是因为这个这个特定的业务部门是如何运作的。)

在上述组织中,我曾在一个数据库中使用它存储客户的各种财务信息。首先,只有一个公式来计算关于客户财务状况的指数,并且该公式以及基于公式的客户状态存储在数据库的存储过程中。然而,随着政府在过去几年中不断改变规则,为了适应政府,已经制定了更多的公式。

因此问题在于:组织中的每个分支机构都有自己独特的编程部门(每个分支机构之间的组织间业务很少),使用相同的财务数据集,但具有不同的公式和操作。

在这种情况下,将公式存储在数据库中的原始模型带来了维护和办公室政治地狱。首先,Data Architect将创建类型化存储过程以适应更改,但很快组织就开始遇到此模型的问题。总部已经确定,每个分支都会维护自己的一组公式,除了该分支以外的任何人都不应该知道所拥有的公式。在这种情况下,数据架构师知道所有公式,并且不符合总部的政策。更改公式的快速步伐也为每个分支之间的测试带来了效率问题,因为每个公式调整都必须通过Data Architect。

在这种情况下,组织面临一个相当深刻的问题:数据库应该提供解释的信息,还是应该只提供没有任何意义的数据?

这是跳到第三方面的好方法。

第三:思想战争:单一与多用途单一与模块化

上述示例清楚地展示了以多用途方式使用的数据。数据虽然对于每个分支保持相同,但在不同的场景中具有不同的解释和用法。这是我的看法。

您的数据库是否存储和提供本质上具有多用途的数据,并且性能不是一个大问题?

如果是,那么我会说,数据库应该简化为只提供数据,任何与数据完整性无关的逻辑都应存储在其他地方。这更像是一种模块化方法:其他人可以插入他们想要的任何操作和解释,但不能插入SQL。

如果问题的任何部分是否定的(即它的单一目的,或者表现是一个很大的问题),并假设没有办公室政治阻碍,那么我会说,单片方法将大部分内容放入数据库中都很好。优先与否,成为一种意识形态的选择。

我的印象是作者在撰写和编辑问题时,支持单一方法的观点。我确实考虑了这种情况,但一般来说,我采用这种方式:

  • 简单的CRUD,没有别的:ORM
  • 基于数据的公式和工作流程:中间件(如CSLA),不在数据库中(除非是性能问题)
  • 报告:绝对在数据库中(出于性能原因)

以上是我的2美分。

答案 28 :(得分:0)

某些逻辑(例如与集相关的操作)往往更好地表示在存储过程中。然而,有时候在编程代码中最好地表示具有许多分支和条件的算法。用于解析支持脚本操作的运行时函数的命令的语法不能在存储过程中实现。

我在存储过程中看到的一个弱点是,您倾向于为应用程序中的新列表或网格获取新的存储过程。或者更糟糕的是,一个存储过程来统治它们,10个参数和case语句来进一步定义它们。此外,存储过程变得巨大,甚至更难调试。

所有这一切,我和你在一起,因为你选择的原因,ORM可能会多次妨碍你。最后,它归结为你如何统治技术。

答案 29 :(得分:0)

一个问题:如果您的数据源是Web服务怎么办?我通过Web服务仅使用分布式数据编写应用程序。我是否希望使用与我的数据源是RDBMS不同的范例来编写它?

如果您从RDBMS切换到Web服务(因为在内部商店中,这不太可能),我不会问你做了什么,我问你从一开始就从Web服务获取数据时你会怎么做?

您的编程模型是否与RDBMS完全不同?如果是,您需要考虑可维护性。如果我们开发的每个应用程序都使用不同的范例进行编程,那么我的开发人员会有一段糟糕的时间。

答案 30 :(得分:0)

好的,我想感谢你们进行了一次引人入胜的讨论。我正在通过Stephen Walther的ASP.NET MVC Framework Unleashed工作,我喜欢它作为一种哲学练习,但我对他的方法需要的管道代码量感到有些惊讶。现在,这并不是使用ORM所固有的--Rails本身就是为了让你摆脱这些内务管理问题,但是我真的在努力思考我是否认为必须编写并维护一个可以由应用程序和将Record类映射到数据库的EntityRecord类。

他对优点的看法是你最终得到了一个可测试的应用程序,测试运行得很快,但坦率地说,我宁愿用一些测试速度来执行实际上在应用程序中的代码。我想当你花费一天时间来逛街并复制属性以便你的测试可以快速运行时,测试尾巴开始摇晃程序员狗 - 他宁愿追逐兔子或者在前面小睡火的。

第二个引用的好处是您可以使用您的应用程序并在不同的数据库上运行它。是的,好吧,也许如果您正在编写像SalesForce这样的东西用于转售或其他东西,这可能是一个目标,但对于90%或更多的应用程序,那么什么呢?我想起了“这是一个美好的生活”中的邻居给了乔治一罐钱并且说:“如果我有一个丈夫的话,我就是在挽救这个离婚。”在你需要它之​​前不要写它。

另一方面,我确实对存储过程有异议。它不一定是固有的使用,而是我工作过的一些脑死亡商店的特征:他们有时会把DBA放在我想写的代码中。我想我不是牛仔,但另一方面,我不喜欢召集一个联合国委员会来增加一个领域。

答案 31 :(得分:0)

老实说,我认为如果您可以通过表格获取数据,那就去吧!但是,当事情变得棘手时,你应该明智地学会如何构建事物以获得一些简单性。

我没有阅读所有的答案,但是常见的问题变得棘手:

  • 代码重复Buggy,代码不稳定
  • 加载静态的巨大类 课程
  • 逻辑无处不在 任何地方(aspx,静态方法,sql, 触发器)
  • 与多个互动 对象,共享共同的功能将 难以理解

至于域名与数据。我认为数据总是会赢,功能对客户来说都很重要。它必须工作。如果你违反了原则,提供了按时运作的东西,我就是重构的支持者。你可以随时回去重构。

也是关于调试器,复杂域的快速说法。我似乎很多人都害怕,因为他们遇到了界面,不了解非常先进的OOP /多态代码中可能的所有杂技。我完全理解,有时候你会迷失方向并且被吓倒。这就是他们制作工具的原因..我不像1000个文件的解决方案那样害怕1000个文件的庞大方法。而且我看到他们都信不信由。

如果你愿意编写测试,你也不会过分担心调试器和代码的转换,那么也有一种快乐的媒介。如果您获得了很好的工具并找到了平衡点,那么您将解决上述所有问题并保持足够的简单易用性。

答案 32 :(得分:0)

我没有看到实体对象与可伸缩性有什么关系,你可能正在谈论使用ORM工具,在这种情况下我同意你的看法。

我对可扩展性非常感兴趣。实体对象永远不会构建高度可伸缩的应用程序,但您必须以正确的方式执行,换句话说,您需要手写DAL,而不是使用某些ORM生成的DAL。实际上这就是为什么我不喜欢ORM,没有什么比手写的DAL更好,我也不使用LINQ,因为我在很多地方读到它有很大的开销。我在我的应用程序中调整每个查询并创建所需的索引,我不会让一些ORM为我生成代码。

我不同意你的观点,Entity对象使代码难以维护,实际上这个架构的目的是让它更容易维护和修改你的代码,这就是我在实践中看到的,我写的spaghetti代码很长一段时间(没有使用3层或n层架构)所以我知道我在说什么。

缓存也需要Entity对象,我想知道如果不使用Entity对象,如何在应用程序中缓存数据,是否使用数据集或数据表?

答案 33 :(得分:0)

好问题!

我更喜欢的一种方法是创建一个迭代器/生成器对象,该对象发出与特定上下文相关的对象实例。通常这个对象包含一些底层的数据库访问内容,但是在使用它时我不需要知道它。

例如,

  

AnswerIterator对象生成AnswerIterator.Answer对象。它会在一个SQL语句中迭代以获取所有答案,另一个SQL语句用于获取所有相关注释。但是在使用迭代器时,我只使用具有此上下文的最小属性的Answer对象。使用一些骨架代码,这几乎是微不足道的。

我发现当我有一个庞大的数据集可以正常工作时,这种方法很有效,当正确完成时,它会为我提供相对容易测试的小型瞬态对象。

它基本上是数据库访问的薄外壳,但它仍然可以在我需要时灵活地抽象它。

答案 34 :(得分:0)

我认为现在企业解决方案中过分强调实体对象。它们不能包含业务层功能,因为它们属于服务层中的服务,或UI特定功能的UI层等。实体对象确实允许设计者在设计应用程序方面做得更好,但它们不一定必须包含其中的所有应用程序逻辑。它们可以是遵循某些规则和接口的愚蠢对象,可用于在它们之上构建其他层,并充当层之间的数据载体。

答案 35 :(得分:0)

我的应用程序中的对象倾向于与数据库一对一关联,但我发现使用Linq To Sql而不是使用sprocs可以更轻松地编写复杂的查询,尤其是能够使用延迟构建它们执行。例如来自于Images.User.Ratings等中的r。这节省了我试图在sql中计算出几个连接语句,并使Skip&对分页采取也简化了代码,而不是必须嵌入row_number& 'over'代码。

答案 36 :(得分:0)

我对存储过程中“锁定你的数据库”的论点赞成感到困惑。我可以使用我的ActiveRecord模型并将其从MySQL移动到Postgres到SQLite,非常感谢。除非我想重写所有内容,否则我无法使用基于proc的任何内容执行此操作。

我认为您的意思是说您正在锁定数据库架构。这个论点更有趣。在某种程度上,我认为它是从一个具有最小单元测试和代码覆盖率的应用程序的角度来论证的 - 你不会改变你的代码的应用程序完全担心你会破坏“某些东西”。

我对基于存储过程的系统的经验很少。我很好奇,在大型应用程序中,您如何管理所有数据关系?在一个页面上,我展示了带有图片的产品。在另一页上,我展示了一个产品和创建它的用户。在另一页上,我展示了一个产品及其评论。在另一个页面上,我需要展示没有图片的产品加上关于它的规格表等等。我有一个有很多关系的数据模型。我假设你没有为每个组合写一个存储过程? DRY原则是我担心的原则。在我重新加入(有效地重新编码)我的关系的地方,我写了多少个查询?而且,当我们谈论锁定模式时,我需要重新编写多少存储过程?

答案 37 :(得分:0)

有趣的问题。几个想法:

  1. 如果您的所有业务逻辑都在您的数据库中,您将如何进行单元测试?
  2. 不会更改您的数据库结构,特别是影响您应用中多个网页的数据库结构,是整个应用中更改的主要麻烦吗?

答案 38 :(得分:0)

我一直在猜测由SQL驱动的关系数据库是否与使用ActiveRecord范例的这些框架没有多大关系。一个基本问题是AR(以及良好的面向对象设计)促使我们分解逻辑;并且SQL根本不适合语句分解。

我想知道对数据库使用isam持久性模型是不是更好的主意;与OO的阻抗匹配更好;就数据作为表格的基本概念达成更多协议;更符合OO持久性的传统工件。一个很好的例子是FK及其关联可以更明确。

RoR有一个数据库slu rep的代表,我怀疑这个问题是很大一部分原因。

是否有人尝试将isam数据库用于ActiveRecord实现?

答案 39 :(得分:0)

我认为您只是习惯于编写特定类型的应用程序,并解决某种问题。你似乎是从“数据库优先”的角度来攻击这个。有很多开发人员将数据持久保存到数据库,但性能不是首要任务。在很多情况下,在持久层上放置抽象会大大简化代码,而性能成本则不是问题。

无论你在做什么,都不是OOP。这没有错,它只是不是OOP,并且将解决方案应用于其他任何问题都没有意义。

答案 40 :(得分:0)

为什么要停在实体对象上?如果在企业级应用程序中没有看到实体对象的值,那么只需使用纯函数/过程语言进行数据访问,然后将其连接到UI。为什么不切掉所有的OO“绒毛”呢?