
Why do we need entity objects?我确实需要就当前接受的企业应用程序设计范例的优点进行一些诚实,周到的辩论。 我不认为实体对象应该存在。 实体对象是指我们倾向于为应用程序构建的典型事物,例如"人","帐户","订单"等。 我当前的设计理念是: (注意:我还使用Java EE构建了企业应用程序,java人士请用等价的.NET示例代替) 我不是反OO。我为不同目的编写了很多类,而不仅仅是实体。我将承认,我编写的大部分类都是静态帮助器类。 我不是在造玩具。我说的是跨多台机器部署的大批量交易应用程序。 Web应用程序,Windows服务,Web服务,B2B交互,您可以命名。 我曾经使用过OR Mappers。我写了一些。我已经使用了Java EE堆栈,CSLA和其他一些等效项。我不仅使用了它们,而且还在生产环境中积极开发和维护了这些应用程序。 我得出了经过实战检验的结论,即实体对象正在妨碍我们前进,没有它们,我们的生活将变得更加轻松。 考虑一个简单的示例:您收到有关应用程序中某个页面无法正常工作的支持电话,可能其中一个字段没有像应有的那样被保留。对于我的模型,分配来查找问题的开发人员仅打开了3个文件。一个ASPX,一个ASPX.CS和一个带有存储过程的SQL文件。该问题可能是存储过程调用中缺少的参数,需要几分钟才能解决。但是对于任何实体模型,您将始终启动调试器,开始逐步执??行代码,最终可能会在Visual Studio中打开15-20个文件。到栈底时,您已经忘记了从哪里开始。我们一次只能记住这么多事情。在不添加任何不必要的层的情况下,软件非常复杂。 开发的复杂性和故障排除只是我苦恼的一方面。 现在让我们谈谈可伸缩性。 开发人员是否意识到每次编写或修改与数据库交互的任何代码时,都需要对对数据库的确切影响进行彻底的分析?不仅仅是开发副本,我的意思是模仿生产,因此您可以看到,对象现在需要的附加列刚刚使当前查询计划无效,并且在1秒内运行的报告现在将需要2分钟,因为您在选择列表中添加了单列?事实证明,您现在需要的索引是如此之大,以至于DBA不得不修改文件的物理布局? 如果您通过抽象让人们离物理数据存储区太远,他们将对需要扩展的应用程序造成破坏。 我不是狂热者。我可以确信,如果我错了,也许我错了,因为对Linq到SQL,ADO.NET EF,Hibernate,Java EE等的大力推动。请仔细考虑您的回答,如果我遗漏了一些我我真的很想知道它是什么,以及为什么我应该改变自己的想法。 [编辑] 看来这个问题突然又活跃起来了,所以现在有了新的评论功能,我已经直接对几个答案发表了评论。感谢您的答复,我认为这是一个健康的讨论。 我可能应该更清楚地知道我在谈论企业应用程序。例如,对于在某人的台式机或移动应用程序上运行的游戏,我真的无法发表评论。 对于几个相似的答案,我不得不在顶部提出一件事:正交性和关注点分离经常被引用为采用实体/ ORM的原因。对我来说,存储过程是我能想到的分离关注点的最佳示例。如果不允许除通过存储过程之外的所有其他对数据库的访问,则理论上可以重新设计整个数据模型,而不会破坏任何代码,只要您保持存储过程的输入和输出即可。它们是按合同编程的完美示例(只要避免使用" select *"并记录结果集即可)。 问一个已经从事该行业很长时间并且使用了长期应用程序的人:在数据库运行期间,有多少个应用程序和UI层来去去了?当有4到5个不同的持久层生成SQL来获取数据时,调整和重构数据库有多难?你什么都不能改变! ORM或生成SQL的任何代码将您的数据库牢牢锁定。 好。 我认为这取决于应用程序"逻辑"的复杂程度以及在何处实现它。如果您所有的逻辑都在存储过程中,而您的应用程序所要做的只是调用这些过程并显示结果,那么开发实体对象确实是在浪费时间。但是对于一个对象之间具有丰富交互关系且数据库只是一种持久性机制的应用程序而言,拥有这些对象可能会有所价值。 因此,我要说的是没有一个"千篇一律"的答案。开发人员确实需要意识到,有时候,过于OO可能导致更多问题,而不是解决的问题。 理论认为,高度凝聚力,松散耦合的实现是前进的道路。 因此,我想您正在质疑这种方法,即分离关注点。 我的aspx.cs文件是否应该与数据库交互,调用sproc并了解IDataReader? 在团队环境中,尤其是在您缺乏技术人员来处理应用程序的aspx部分的情况下,我不需要这些人能够"接触"这些东西。 将域与数据库分开可以保护我免受数据库结构性更改的影响,这肯定是件好事吗?确保数据库的有效性绝对重要,因此,让一位最擅长于此工作的人员可以在一处处理该工作,而对系统的其余部分的影响则尽可能小。 除非我对您的方法有误解,否则数据库中的一项结构更改可能会对应用程序的表面产生很大的影响。我看到关注点的分离使我和我的团队可以将其最小化。此外,团队的任何新成员都应该更好地理解这种方法。 另外,您的方法似乎主张将应用程序的业务逻辑驻留在数据库中?我觉得这很不对劲,SQL确实擅长查询数据,而恕我直言,不能表达业务逻辑。 尽管有趣的想法,尽管它感觉到与aspx中的SQL相距仅一步之遥,但与我过去糟糕的非结构化asp时代相比,这让我感到恐惧。 原因之一-将您的域模型与数据库模型分开。 我要做的是使用测试驱动开发,因此我首先编写了UI和Model层,并对Data层进行了模拟,因此UI和Model围绕领域特定对象构建,然后将这些对象映射到我正在使用的技术上数据层。让数据库结构确定应用程序的设计是一个坏主意。在可能的情况下,首先编写该应用程序,并让它影响数据库的结构,而不是相反。 对我来说,它归结为我不希望我的应用程序关心数据的存储方式。我可能会因为这么说而被打耳光...但是您的应用程序不是您的数据,数据是应用程序的工件。我希望我的应用程序从客户,订单和物料的角度来考虑,而不是像DataSets,DataTables和DataRows ... cuz这样的技术来思考,因为他们知道这些数据将持续多久。 我同意总是存在一定程度的耦合,但是我更喜欢耦合向上而不是向下。比起改变树干,我可以更容易地调整其四肢和叶子。 我倾向于保留用于报告的存储过程,因为查询的确比应用程序的常规数据访问更容易处理。 我还倾向于认为,在这种情况下尽早进行适当的单元测试,就像不保留一列很可能不是问题。
埃里克 我的职业生涯遵循相似的轨迹,并得出了相同的结论。当然,我们被视为异教徒,但看上去很滑稽。但是我的东西行之有效。 每一行代码都应引起怀疑。 我想用一个与您提出的例子类似的例子来回答。 在公司上,我必须为产品构建一个简单的CRUD部分,并建立所有实体和单独的DAL。后来,另一个开发人员不得不更改一个相关表,他甚至重命名了几个字段。我必须更改以更新表单的唯一文件是该表的DAL。 (在我看来)实体为项目带来的是: 正交性:一层中的更改可能不会影响其他层(当然,如果您对数据库进行了巨大的更改,它将在所有层中蔓延,但是大多数较小的更改不会)。 可测试性:无需接触数据库即可测试逻辑。这可以提高测试的性能(允许您更频繁地运行它们)。 关注点分离:在大型产品中,您可以将数据库分配给DBA,他可以优化数据库。将模型分配给具有设计所需知识的业务专家。将个人表单分配给对Web表单等内容更有经验的开发人员。 最后,我想补充一下,大多数ORM映射器都支持存储过程,因为这就是您所使用的。 干杯。 我认为您可能对此话题"咬牙切齿"。泰德·纽亚德(Ted Neward)称其为"越南计算机科学"时,并没有表现出任何轻率。 我绝对可以保证的一件事是,它将改变任何人对此事的观点,这一点在无数其他博客,论坛,播客等上已经得到了证明。 对一个有争议的话题进行公开讨论和辩论当然是可以的,只是这一点已经做了很多次,双方都同意不同意并开始编写软件。 如果您想对双方都做进一步的阅读,请参阅Ted博客上的文章,Ayende Rahein,Jimmy Nilson,Scott Bellware,Alt.Net,Stephen Forte,Eric Evans等。 @Dan,对不起,这不是我想要的东西。我知道理论。您的陈述"是一个非常糟糕的主意"并没有得到一个实际例子的支持。我们正在尝试以更少的时间,更少的人员,更少的错误来开发软件,并且我们希望能够轻松进行更改。根据我的经验,您的多层模型在上述所有类别中都是负面的。特别是关于使数据模型成为您最后要做的事情。从第一天起,物理数据模型就必须成为重要的考虑因素。
我们还应该讨论实体实际上是什么的概念。
丰富的领域模型具有价值。这就是域驱动设计的全部意义。 如果我们可以应用面向对象技术来分析,建模,设计和实现我们的业务问题,那么对于非平凡应用程序的可维护性和可扩展性来说,这是一个巨大的优势! 您的实体和表之间存在差异。实体应该代表您的模型,表只代表模型的数据方面! 数据的寿命确实比应用程序长,但是请考虑一下大卫·拉里比(David Laribee)的这句话:模型永远存在……数据是一种快乐的副作用。 有关此主题的更多链接:
实体对象可以促进在应用程序层上的缓存。祝你好运,缓存数据读取器。 除了抽象和松散耦合外,实体对象还有其他很好的理由。我最喜欢的一件事是DataReader或DataTable无法获得的强类型。另一个原因是,如果做得好,适当的实体类可以通过对特定于领域的术语使用一流的构造来使代码更具可维护性,这些领域特定的术语使任何看代码的人都可能理解,而不是使用一堆带有字段名的字符串用于索引DataRow。存储过程实际上与ORM的使用正交,因为许多映射框架使您能够映射到sproc。 我不会考虑用sprocs + datareader代替好的ORM。使用存储过程时,您仍然受过程类型签名的束缚,并与之紧密耦合,该过程使用与调用代码不同的类型系统。存储过程可以进行修改,以适应其他选项和架构更改。在架构可能发生更改的情况下,存储过程的替代方法是使用视图-您可以将对象映射到视图,然后在更改视图时将视图重新映射到基础表。 如果您的经验主要包括Java EE和CSLA,那么我可以理解您对ORM的厌恶。您可能想看一下LINQ to SQL,它是一个非常轻量级的框架,主要是与数据库表的一对一映射,但是通常只需对其进行较小的扩展即可成为成熟的业务对象。 LINQ to SQL还可以将输入和输出对象映射到存储过程的参数和结果。 ADO.NET实体框架具有附加的优势,即您的数据库表可以看作是彼此继承的实体类,也可以看作是聚合到单个实体中的多个表的列。如果需要更改架构,则可以更改从概念模型到存储架构的映射,而无需更改实际的应用程序代码。同样,这里可以使用存储过程。 我认为,与应用程序的可伸缩性问题相比,企业中更多的IT项目失败是由于代码的不可维护性或开发人员生产力低下(例如,在存储过程编写和应用程序编写之间进行上下文切换而导致的)。
我发现你的问题真的很有趣。 真有趣的问题。老实说,我无法证明实体为什么很好。但是我可以分享我为什么喜欢他们的观点。像这样的代码
不必担心订单来自哪里-从数据库,从Web请求,从单元测试等。它使此方法更明确地声明其确切要求,而不是采用DataRow并记录其期望具有的列和它们应具有的类型是。如果您以某种方式将它实现为存储过程,则同样适用-您仍然需要将记录id推送到它,而数据库中不必存在它。 该方法的实现将基于订单抽象,而不是基于数据库中的精确程度。我执行的大多数此类操作实际上并不取决于如何存储此数据。我确实了解到,出于性能和可伸缩性的目的,某些操作需要与数据库结构耦合,仅以我的经验来看,其中并没有太多。以我的经验,经常知道Person具有.getFirstName()返回字符串,而.getAddress()返回地址,并且地址具有.getZipCode()等是足够的,并且不必关心哪些表涉及存储该数据。 如果您必须处理所描述的问题(例如,当其他列中断报告性能时),那么对于您的任务,DB是至关重要的部分,实际上您应该尽可能地接近它。虽然实体可以提供一些方便的抽象,但是它们也可以隐藏一些重要的细节。 可伸缩性在这里很有趣-大多数需要巨大可伸缩性的网站(例如facebook,livejournal,flickr)倾向于使用DB-ascetic方法,这是因为尽可能少地使用DB,并且可伸缩性问题通过缓存(尤其是通过使用RAM)来解决。 http://highscalability.com/上有一些有趣的文章。 我还想补充一下Dan的答案,即分离两个模型可以使您的应用程序可以在不同的数据库服务器甚至数据库模型上运行。 如果您需要通过负载平衡多个Web服务器来扩展应用程序怎么办?您可以在所有Web服务器上安装完整的应用程序,但是更好的解决方案是让Web服务器与应用程序服务器通信。 但是,如果没有任何实体对象,那么它们就没什么好谈的了。 我并不是说如果它是一个简单的,内部的,寿命短的应用程序,则不应编写整体。但是,一旦它变得相当复杂,或者应该持续相当长的时间,您确实需要考虑一个好的设计。 这样可以节省维护时间。 通过将应用程序逻辑与表示逻辑和数据访问分开,并在它们之间传递DTO,可以将它们分离。允许他们独立更改。 您可能会在comp.object上发现这篇文章很有趣。 我并没有声称同意或不同意,但这很有趣,而且(我认为)与此主题相关。 一个问题:如果所有业务逻辑都被困在数据库中,那么如何处理断开连接的应用程序?
在我感兴趣的企业应用程序类型中,我们必须处理多个站点,其中一些站点必须能够在断开状态下运行。 为了将域层保留在数据库的存储过程中,您必须坚持使用一种需要永久访问数据库的应用程序。 可以在特定类别的环境中使用,但肯定不能涵盖企业应用程序的全部范围。 我真的不确定您认为"企业应用程序"是什么。但是,我给您的印象是,您将其定义为内部应用程序,其中RDBMS可以固定使用,并且该系统不必与任何其他系统(内部或外部)都可以互操作。 但是,如果您有一个包含100个表的数据库,这些表等于每个表的4个存储过程,仅用于基本的CRUD操作,则需要维护400个存储过程,这些存储过程不是强类型的,因此容易出现拼写错误,也不能进行单元测试。当您获得一名新的CTO时,会遇到什么情况,该CTO是一名开源传道者,并且希望将RDBMS从SQL Server更改为MySql?
如今,无论企业应用程序还是产品,许多软件都在使用SOA,并且对公开Web服务有一些要求,至少我本人并且曾经参与其中。 软件设计没有灵丹妙药,它实际上取决于优先级在哪里,对我而言,它在单元可测试代码和松散耦合的组件中,可以很容易地被任何客户端使用。 只是我的2美分 @jdecuyper,我经常对自己重复的一个格言是"如果您的业务逻辑不在数据库中,那只是一个建议"。我认为保罗·尼尔森(Paul Nielson)在他的一本书中曾说过。应用程序层和用户界面来来往往,但是数据通常会生存很长时间。 如何避免实体对象?存储过程多为。我也自由地承认,无论您是否打算,业务逻辑都倾向于遍及应用程序的所有层。一定数量的耦合是固有的并且不可避免的。 最近我一直在想着同样的事情。我曾经是CSLA的重度用户,我很喜欢说"您的所有业务逻辑(或至少尽可能合理地封装在业务实体中)"的纯洁性。 我已经看到,在数据库的设计与您使用数据的方式不同的情况下,业务实体模型可以提供很多价值,在许多业务软件中都是如此。 例如,"客户"的概念可能由"客户"表中的主记录,客户已下达的所有订单以及所有客户的员工及其联系信息以及"客户"的某些属性组成可以从查找表确定客户及其子级。从开发的角度来看,能够与Customer作为单个实体合作真的很不错,因为从业务角度来看,Customer的概念包含所有这些内容,并且关系可以在数据库中执行,也可以不执行。 尽管我赞赏"如果您的业务规则不在数据库中,这只是一个建议"的说法,但我也相信您不应该设计数据库来强制执行业务规则,而应该将其设计为高效,快速和规范化。 就是说,正如上面其他人提到的那样,没有"完美的设计",该工具必须适合工作。但是使用业务实体确实可以帮助维护和提高生产率,因为您知道去哪里修改业务逻辑,并且对象可以以直观的方式对现实世界的概念进行建模。 我想为OO和RDB之间的距离问题提供另一个角度:历史。 任何软件都具有现实模型,在某种程度上是现实的抽象。没有计算机程序可以捕获现实的所有复杂性,而编写程序只是为了解决现实中的一系列问题。因此,任何软件模型都是现实的缩影。有时,软件模型会迫使现实降低自身。就像您想让汽车租赁公司为您预订任何一辆汽车,只要它是蓝色且有合金的,但由于您的要求不适合计算机,操作员无法遵守。 RDB源自将信息放入表格的一种非常古老的传统,称为会计。记帐是在纸上进行的,然后是打孔卡,然后是计算机。但是会计已经成为现实。会计一直迫使人们遵循其制度,直到它成为公认的现实。这就是为什么制作用于会计的计算机软件相对容易的原因,会计早在计算机问世之前就有其信息模型。 鉴于良好的会计系统的重要性以及您得到任何业务经理的认可,这些系统已经变得非常先进。现在,数据库基础非常牢固,并且毫不犹豫地将重要数据保存在如此值得信赖的环境中。 我猜当人们发现现实的其他方面比会计(已经是模型)更难建模时,OO一定会出现。 OO已经成为一个非常成功的想法,但是OO数据的持久性却相对欠发达。 RDB / Accounting获得了轻松的胜利,但是OO是一个更大的领域(基本上所有不会计的领域)。 我们中的许多人都想使用OO,但我们仍然希望安全地存储数据。还有什么比像受人尊敬的会计系统那样存储我们的数据更安全的呢?这是一个诱人的前景,但我们都遇到了同样的陷阱。与RDB行业进行了大量努力相比,很少有人会想到OO持久性,RDB行业已经受益于会计的传统和职位。 Prevayler和db4o是一些建议,我敢肯定还有其他一些我没听说过的建议,但是似乎没有任何一个可以说是冬眠了。 对于多用户应用程序,尤其是Web应用程序,似乎甚至没有认真考虑将对象存储在良好的旧文件中。 在我为消除OO和RDB之间的鸿沟所做的日常努力中,我尽可能地使用OO,但要尽量减少继承。我不经常使用SP。我只会在看起来像会计的方面使用高级查询内容。 当鸿沟永久关闭时,我会感到惊讶。我认为该解决方案将在Oracle启动" Oracle对象实例库"之类的东西时出现。要真正流行起来,它必须有一个令人放心的名称。 埃里克 没有人阻止您选择您想要的框架/方法。如果您要走"以数据驱动/存储过程为动力"的道路,那么一定要走!尤其是,如果确实能够帮助您按时按时交付应用程序。 需要注意的是(您的问题的另一面),所有业务规则都应位于存储过程中,而您的应用程序仅是瘦客户端。 话虽如此,如果您在OOP中进行申请,则应遵循相同的规则:保持一致。遵循OOP的原则,包括创建实体对象以表示您的域模型。 这里唯一真正的规则是一致性一词。没有人阻止您以数据库为中心。没有人阻止您进行老式的结构化(又称功能/程序)程序。地狱,没人阻止任何人编写COBOL风格的代码。但是,如果应用程序希望获得任何程度的成功,那么它必须非常,非常一致。 有时,您的应用程序和数据层并没有那么紧密地耦合在一起。例如,您可能有一个电话计费应用程序。稍后,您将创建一个单独的应用程序,以监控电话使用情况,以便a)更好地向您宣传b)优化您的电话计划。 这些应用程序有不同的关注点和数据要求(即使数据来自同一数据库),它们也会驱动不同的设计。如果让数据库来驱动代码,您的代码库可能会导致绝对混乱(在任何一个应用程序中),并且将使维护工作陷入噩梦。 目前时间不多,但就在我头顶上。 实体模型使您可以为数据库(和其他可能的系统)提供一致的接口,甚至可以超出存储过程接口可以提供的接口。通过使用企业范围的业务模型,可以确保所有应用程序一致地影响数据,这是非常重要的。否则,您将获得错误的数据,这简直就是邪恶。 如果只有一个应用程序,那么无论该应用程序或数据有多大,您实际上都没有"企业"系统。在这种情况下,您可以使用与您所谈论的类似的方法。请注意,如果您决定将来扩展系统,将需要做的工作。 不过,您应该牢记以下几点(IMO): (以下情况除外)。对不起 知道很多人认为 这可以节省大量时间,但是我已经 从来没有找到一个可以 生成比 我会写什么,经常 代码简直太恐怖了。您 也常常会产生一吨 永远不会使用的SQL代码。 这里的异常很简单 模式,例如查找表。 很多人被带走 虽然。 具有与数据存储逻辑分离的域逻辑的应用程序适用于任何种类的数据源(数据库或其他)或UI(Web或Windows(或Linux等))应用程序。 您几乎陷在数据库中,如果您对对当前数据库系统感到满意的公司,这也不错。但是,由于数据库会随着时间的推移而发展,因此可能会出现一个新的数据库系统,该数据库系统确实非常整洁,可以供贵公司使用。如果他们想切换到Web服务的数据访问方法怎么办(比如有时面向服务的体系结构会这样做)。您可能必须在各处移植存储过程。 此外,域逻辑还会抽象出UI,这在具有不断发展的UI的大型复杂系统中(尤其是当他们不断寻找更多客户时)尤其重要。 同样,尽管我同意对存储过程与域逻辑的问题没有明确的答案。我正处于域逻辑阵营中(并且我认为它们会随着时间的流逝而获胜),因为我相信,精心设计的存储过程比精心设计的域逻辑更难维护。但这是另一场辩论 老实说,我想如果您能摆脱表单中的数据,那就去吧!但是,当事情变得很棘手时,您应该明智地学习如何构造事物以使其变得简单。 我还没有阅读所有答案,但是常见的问题很棘手:
至于域与数据。我认为数据将永远赢,功能对客户至关重要。它必须工作。我支持重构,只要您违反原则就可以按时交付有用的东西,那么您可以随时返回并进行重构。 也是有关调试器,复杂域的快速介绍。我似乎很多人都害怕,因为他们碰到了界面,不了解非常高级的OOP /多态代码中可能出现的所有杂技。我完全理解,有时候您会迷路和震慑。这就是为什么他们制作工具的原因。与一千行的繁琐方法相比,与一千个文件的解决方案相比,我不惧怕这种解决方案。我见过都相信或不相信。 如果您愿意编写测试,也不必担心调试器和通过代码逐步调试,那么这里也有一个不错的选择。如果您拥有良好的工具并找到平衡点,则可以解决上述所有问题,并使事情简单到可以解决的程度。 以非常通用的方式解决大问题的软件适用于许多实际情况,其本身必然会带来性能成本。它需要代码来处理所有通用性,并且代码需要花费时间才能运行。 同样,通过抽象层的降级总是会发现有些东西要花一些钱,有些东西要花很多钱,而这些差异被抽象所掩盖了。抽象给开发人员提供了与外界隔绝的隔离,这总是使开发人员随便引入比必要的更为昂贵的操作。 从仅性能的角度和仅可扩展性能的角度来看,关于此问题的其他任何说法都可以避免,由于与自己数据??库的现实状况之间的额外隔离所造成的双重打击将在性能上有所回报。 我目前正忙于解决这些问题引起的性能问题,而这些问题却是可怕的怪物。 我最近偶然发现了这个问题。意识到这个问题已经很老了,并且有很多答案,我知道我的回答很多都没有被看过。不过,我想在这里留下我的评论。 我将从三个方面看待这个问题。但在此之前,我必须声明:在十分之八的程序员中,来自命令性/ OO设计世界(C / C ++,JAVA,C#等)的程序员不知道如何编写优化的高效SQL代码。根据我的经验,很少有人会同时在应用程序开发和SQL开发方面做得很好。 话虽如此,我想提出三个方面来研究这个问题。 第一:关注点分离不是根据计划,而是组织层次结构。 坦白说,这个世界上有许多种"企业",每一种都有自己的组织等级,其等级因历史和哲学而异。在与我合作过的一家特定公司中,程序员无法修改或开发数据库。他们可以读取和使用数据库API(即SQL Server中的存储过程),但不能直接读取数据库,并且不能编写任何查询或存储过程。 任何数据库请求(数据或功能)都必须委派给另一个角色:Data Architect。他/她将是负责数据库开发和维护的人员。 (尽管维护工作应该由DB Admin来完成。)在这种环境下,存储过程只能消耗;即使PROD环境中的存储过程的源也将被加密,并且不允许程序员看到SP的源。 但是,在其他一些组织中,期望程序员进行所有方面的开发,包括接口,中间件和数据存储。这是大多数情况。 在这两种情况下(尽管第一种情况是相当极端但真实的),它将影响您如何看待作者的问题。在第一种情况下,我想说作者会同意数据架构师的角色,但是组织中任何非数据库程序员都会大为鄙视。但是,在第二种情况下,由于我先前关于许多开发人员不知道如何编写良好的SQL代码的声明(并且通常也不想处理它),因此自然会选择一种更简单的方法:ORM。 第二:数据库的作用:纯数据存储多达不同的解释,还是提供预定义的信息方案? 定义:"数据"是原始的,而"信息"则被解释。 在许多实际情况下,数据库仅被视为纯数据存储。它可能包含数据逻辑(例如,关系数据的完整性),但不包含业务逻辑(例如,不是由于数据的性质而是因为此特定业务部分的工作原理而将任何公式应用于数据)。 在与我合作的上述组织中,它在一个数据库中存储了客户的各种财务信息。首先,只有一个公式可以计算有关客户财务状况的指标,并且该公式以及基于该公式的客户状态存储在数据库的存储过程中。但是,由于政府在过去几年中不断更改规则,因此已经创建了更多的公式来适应政府。 因此出现了问题:组织中的每个分支机构都有自己独立的编程部门(每个分支机构之间几乎没有组织间业务),它们使用相同的财务数据集,但是使用的公式和操作不同。 在这种情况下,将公式存储在数据库中的原始模型给维护和办公室带来了麻烦。最初,Data Architect将创建类型化的存储过程来适应更改,但是很快组织就开始对此模型产生麻烦。总部已确定,每个分支机构都将维护自己的公式集,除该分支机构外,没有人会知道自己拥有的公式。在这种情况下,数据架构师知道所有公式,这与总部的政策不太吻合。更改公式的快速步伐还给每个分支之间的测试带来了效率问题,因为每个调整的公式都必须经过数据架构师。 在这种情况下,组织面临一个相当深远的问题:数据库应该提供解释后的信息,还是只提供没有任何意义的数据? 这是跳入第三个方面的好方法。 第三:思想战:单用途还是多用途,整体还是模块化? 前面提到的示例是对以多种方式使用的数据的清晰演示。尽管每个分支的数据都相同,但在不同的场景中数据具有不同的解释和用法。这是我的看法。 您的数据库是否存储和服务本质上具有多用途且性能不是大问题的数据? 如果是的话,那么我应该说,数据库应该简化为仅用于数据服务,并且任何与数据完整性无关的逻辑都应该存储在其他位置。这更多是一种模块化方法:其他人可以插入他们想要的任何操作和解释,但不能插入SQL。 如果问题的任何部分都是负面的(即,它的目的是单一的,或者性能是一个很大的大问题),并且假设没有办公室政治的阻碍,那么我想说的是将多数内容放入数据库的整体方法很好不管是否愿意,这都成为意识形态的选择。 我的印象是,作者在编写和编辑问题时支持整体方法的观点。 我确实视情况而定,但总的来说,我的做法是: 以上是我的2美分。 好。 诸如与集合相关的操作之类的某些逻辑倾向于在存储过程中更好地表示。但是,有时在编程代码中最好地表示具有许多分支和条件的算法。存储过程中无法实现用于解析支持脚本操作的运行时功能的命令的语法。 我在存储过程中看到的一个弱点是,您倾向于为应用程序中的新列表或网格获得一个新的存储过程。或更糟糕的是,一个存储的proc可以将它们全部规则化,另外还有10个参数和case语句来进一步定义它们。此外,存储的proc变得非常庞大,甚至更加难以调试。 综上所述,我支持您,ORM可能会因您选择的原因而多次受阻。最后,归结为您如何控制技术。 为什么停在实体对象上?如果您在企业级应用程序中看不到实体对象的价值,则只需使用纯功能/过程语言进行数据访问并将其连接到UI。为什么不切掉所有的OO"绒毛"呢? 一个问题:如果您的数据源是Web服务该怎么办?我只通过Web服务使用分布式数据编写应用程序。我是否希望使用与我的数据源是RDBMS时不同的范例来编写? 我不是问您从RDBMS切换到Web服务时会怎么做(因为在内部商店中这不太可能),我问的是数据从一开始就来自Web服务时您会怎么做? 您的编程模型与RDBMS相比是否大不相同?如果是这样,则需要考虑可维护性。如果他们跳入的每个应用程序都使用不同的范例进行编程,那么我的开发人员将度过一个糟糕的时光。 有趣的问题。一些想法: 好吧,我要感谢您的精彩讨论。我正在通过Stephen Walther的ASP.NET MVC Framework Unleashed进行工作,我喜欢它作为一种哲学练习,但是对于他的方法需要大量的代码,我感到有些震惊。现在,这并不是使用ORM所固有的-Rails以将您从此类整理工作中解放出来而感到自豪,但是我真的在为是否必须编写和维护一个单独的Record类(可以由该类使用)而挣扎。应用程序和一个将Record类映射到数据库的EntityRecord类。 他的好处在于,您最终会得到一个可测试的应用程序,其中的测试可以快速运行,但是坦率地说,我宁愿以某种测试速度来执行应用程序中实际存在的代码。我认为,当您整日忙于搜索和复制属性以使测试能够快速运行时,测试尾巴已经开始摇晃程序员的狗,他们宁愿追赶兔子或在前面小睡一下火。 引用的第二个好处是您可以使用您的应用程序并在其他数据库上运行它。是的,好的,也许如果您正在编写诸如SalesForce的转售之类的东西,那可能是一个目标,但是对于90%或更多的应用程序来说,那又是什么呢?我想起了《这是美好的生活》中的邻居,那人给了乔治一罐钱,他说:"如果我有丈夫,我会把它存为离婚。"直到需要时才写它。 另一方面,我确实对存储过程有异议。它的使用不一定是固有的,而是我工作过的一些脑力衰竭商店的功能:他们有时将DBA放在我要编写的代码中。我想以为自己不是牛仔,但相反,我不想召集联合国委员会在表格中添加字段。 好问题! 我更喜欢的一种方法是创建一个迭代器/生成器对象,该对象发出与特定上下文相关的对象实例。通常,此对象包装一些基础数据库访问内容,但使用它时我不需要知道。 例如,
我发现,当我有一个庞大的数据集需要处理时,这种方法就很好用,而且如果正确完成,它可以为我提供相对较小的临时对象,这些对象相对易于测试。 从本质上讲,它只是数据库访问方面的薄板,但仍为我提供了在需要时对其进行抽象的灵活性。 我看不到实体对象与可伸缩性有什么关系,您可能正在谈论使用ORM工具,在这种情况下,我同意您的观点。 我对可伸缩性非常感兴趣。实体对象永远不会以您的方式构建高度可扩展的应用程序,但您必须以正确的方式进行操作,换句话说,您需要手写的DAL,而不是使用某些ORM生成的DAL。实际上,这就是为什么我不喜欢ORM的原因,没有比手写DAL更胜一筹的了,因为在许多地方我读到LINQ开销很大,所以我也不使用LINQ。我调整应用程序中的每个查询并创建所需的索引,但不要让一些ORM为我生成代码。 我不同意Entity对象会使代码难以维护,实际上,该体系结构的整个目的是使维护和修改代码变得更加容易,这是我在实践中看到的,我为很长时间(没有使用3层或n层架构),所以我知道我在说什么。 缓存还需要实体对象,我想知道如果您不使用实体对象,如何使用数据集或数据表,如何在应用程序中缓存数据? 每种方法都有优势。它们对于特定问题的适当性必须根据具体情况进行判断。 我全心全意地相信,正如其他人所指出的那样,实体(因此也就是面向对象)设计简化了其他复杂的业务逻辑。但是我认为,基于实体的设计的最大优势是通过定义明确的输入和输出实现模块化,这在数据库外部和面向对象的模型中更容易实现。我将在下面详细说明。
我是Linux用户。 Unix哲学的一个观点是,开发人员应该"编写处理文本流的程序,因为那是一个通用接口"。对于Linux来说确实如此,因为它是非常以文本为中心的。您可以将不相关的进程链接在一起以实现新的东西,例如 现在,我不认为文本流适合任何地方。文本流是通用的,但不是通用的。我的开发理念是"编写具有明确定义的输入和输出的程序"。我在这里谈论的输入/输出不一定是标准的输入/输出,也不一定是文本的-它可能是命令行程序的参数,通过网络套接字发送的原始字节,在各层之间传递的内存数据结构从旧的Input-Process-Output"黑匣子"角度考虑软件,使您可以像使用Unix中的命令行实用程序那样组成应用程序-单独使用一层薄薄的胶水将它们连接在一起。
例如,假设您正在为澳大利亚新南威尔士州的出生,死亡和婚姻编写软件。登记孩子的出生信息时,操作员输入详细信息,扫描签名的表格,然后单击"提交"按钮。点击"提交"按钮将发出 模块化并不仅限于抽象持久性机制。例如,您可以编写一个FastCGI"胶水层"以使您的应用程序启用Web:Web服务器接受一个"输入" HTTP请求,该服务器向"胶水层"发出一个"输出" FastCGI请求。您的FastCGI"胶水层"接受此作为输入,并将其转换为适合您的应用程序的输出形式。您的应用程序接受输入命令并发出事件或错误,这些事件或错误可以由其他"胶合层"(例如上面给出的SQL和Neo4j示例)拾取。 模块化几乎可以在任何方向上继续。您可以具有命令行界面或GUI界面。您可以创建一个全面的自动化测试套件。您可以打开由第三方编写脚本的应用程序。这里的许多概念涉及域驱动设计,命令查询责任隔离和事件源,这三个相互关联的模式非常强大。 当使用基于实体的方法时,有许多相关的体系结构。例如,有Jeffrey Palermo的洋葱架构和Alistair Cockburn的Ports and Adapters(或六角建筑)。所有这些架构的共同点是通过定义的输入和输出实现模块化和抽象化,而不管这些输入/输出边界是否在单个程序中,或者它们是否跨越多个进程甚至是网络。 基于实体的方法提供了模块化和灵活性。但是,此方法有一些缺点,其中三个很重要: 首先,初期投资高。这意味着这种方法对范围较小的项目没有意义。 其次,您必须编写的粘合代码数量可能会很大。编写胶粘代码可能很乏味,但也可能会有所收获。例如,假设您的应用程序作为存储后端与PostgreSQL松散集成。当公司主管决定该应用程序应支持Microsoft SQL Server时,如果在预定日期之前并低于预算,就可以达到目标(并提高团队士气)。 第三,我的经验告诉我,基于实体的方法可能比简单的SQL解决方案更糟,这取决于实现它的人员的专业知识。例如,如果实体优先方法充满了getter和setter,而这些方法仅是数据库表的内存内表示形式,则可以确定问题并未得到考虑。像这样的情况使开发人员想知道"为什么我们不只是编写SQL?"是可以理解的。 参考文献: 好。 我对支持存储过程的"锁定数据库"一词感到困惑。我可以采用ActiveRecord模型,并将其从MySQL迁移到Postgres再迁移到SQLite,非常感谢。除非我想全部重写它们,否则我无法使用任何基于proc的存储方式执行此操作。 我假设您的意思是您将数据库模式牢牢锁定。这种说法更有趣。从某种程度上讲,我认为这是从具有最小的单元测试和代码覆盖率的应用程序的角度出发的-出于纯粹的恐惧,您不会更改代码的应用程序将破坏"某些东西"。 我对基于存储过程的系统的经验很少。我很好奇,在大型应用程序中,您如何管理所有数据关系?在一页上,我显示带有图片的产品。在另一页上,我显示了产品和创建产品的用户。在另一页上,我显示了产品及其评论。在另一页上,我需要显示没有图片的产品,并附有关于它的规格表……等等。我有一个具有很多关系的数据模型。我假设您没有为每种组合编写存储的proc吗?我担心的是DRY原则。我在重新左连接(有效地重新编码)我的关系的地方写了几个查询?而且,当我们谈论锁定架构时,我将需要重写多少个存储过程? 我认为,如今企业解决方案中过于强调实体对象。它们不能包含业务层功能,因为它们属于服务层的服务或UI特定功能的UI层等。实体对象的确可以使设计人员在设计应用程序方面进行更好的思考,但不一定必须在其中包含所有应用程序逻辑。它们可以是遵循某些规则和接口的哑对象,并且可以用于在它们之上构建其他层,并充当层之间的数据载体。 我一直在推测,由SQL驱动的关系数据库是否与使用ActiveRecord范式的这些框架相互矛盾。一个基本的问题是,AR(以及良好的OO设计)驱使我们分解逻辑。 SQL根本不适合语句分解。 我想知道对于数据库使用isam持久性模型是否会更好?与OO更好的阻抗匹配;在表数据的基本概念上达成更多共识;与OO持久性的常规工件更加一致。一个很好的例子是FK及其关联可以更加明确。 RoR表示自己是数据库专家,我怀疑这个问题很大一部分原因。 有没有人尝试将isam数据库用于ActiveRecord实现? 我的应用程序中的对象往往与数据库一对一关联,但是我发现使用Linq To Sql而不是sprocs可以使编写复杂查询变得更加容易,尤其是能够使用延迟执行来构建它们。例如从Images.User.Ratings中的r等位置获得。这使我免于尝试在sql中计算多个join语句,并且使用Skip&Take进行分页也简化了代码,而不必嵌入row_number和" over"代码。 我认为您只是习惯于编写特定类型的应用程序并解决特定类型的问题。您似乎从"数据库优先"的角度进行攻击。有很多开发人员可以将数据持久存储到数据库中,但是性能并不是重中之重。在很多情况下,将抽象放在持久层上可以大大简化代码,而性能成本却不是问题。 无论您做什么,都不是OOP。没错,这不是面向对象的,将解决方案应用于所有其他问题也没有意义。 |