为什么我们需要实体对象?[关闭]


139

我确实需要就当前接受的企业应用程序设计范例的优点进行一些诚实,周到的辩论。

我不认为实体对象应该存在。

实体对象是指我们倾向于为应用程序构建的典型事物,例如“人”,“帐户”,“订单”等。

我当前的设计理念是:

  • 所有数据库访问都必须通过存储过程来完成。
  • 每当需要数据时,调用存储过程并遍历SqlDataReader或DataTable中的行

(注意:我还使用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的原因。对我而言,存储过程是我能想到的分离关注点的最佳示例。如果不允许除通过存储过程之外的所有其他对数据库的访问,则只要您维护存储过程的输入和输出,理论上就可以重新设计整个数据模型并且不破坏任何代码。它们是按合同编程的完美示例(只要您避免“选择*”并记录结果集)。

问一个已经从事该行业很长时间并且使用了长期应用程序的人:在数据库运行期间,有多少个应用程序和UI层来去去了?当有4到5个不同的持久层生成SQL来获取数据时,调整和重构数据库有多难?你什么都不能改变!ORM或生成SQL的任何代码将您的数据库牢牢锁定


通过阅读您的问题,我们非常相似,而且我想知道多年来完全相同的事情(因为听说了第三方实体框架,现在是微软的框架)
pearcewg,2009年

1
您是说业务逻辑是辅助对象还是存储的proc中的对象?我问的是很多人似乎认为您稍后再说...但是我想您说的是您仍然在编码对象中具有业务逻辑,您只是从数据库中直接获取数据并使用该数据,而不是ORM或映射到专用对象来保存数据。我倾向于也有同样的感觉-但我目前也在评估EF4,看是否值得。
炼金术

“创新的消费者通常是被搞砸的人。” -有经验的人
维吾尔族Gümüşhan

我继承了一个具有2500多个SPROC的系统,在该系统中,该应用程序仅被视为激活SPROC并了解其输出的一种方法。每个读取和写入的数据都有其自己的SPROC。没有中央控制点。它是可怕的,与花岗岩差不多。我考虑优化数据库。2500 SPROCS将我放在了我的位置。与具有组织良好的域层和可重复使用的DAL代码的系统相比,它看起来构思不当,并且是一个噩梦。简单的任务需要花费数小时,并且正在破坏灵魂。SPROC应该用于高负载或特殊方法IMO
trucker_jim 2014年

关于您的“调试”示例:通过单元测试,您可以更快地知道哪里出了问题。
MarioDS '16

Answers:


59

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

因此,我想说的是没有一个“千篇一律”的答案。开发人员确实需要意识到,有时候,过于OO可能导致更多问题,而不是解决的问题。


克里斯托弗(Kristopher),看来您通过从另一个问题链接到此问题而复活了此问题。我想知道您所说的“丰富的交互”是什么意思,而在没有对象的情况下实现它们是不切实际的呢?
Eric Z Beard

4
可以用对象完成的任何事情也可以在没有对象的情况下完成。我发现,OO设计通常比非OO方法更容易执行“复杂”的事情,但是我知道它并不适合所有人。
克里斯托弗·约翰逊

我同意-“何时使用对象”的答案取决于对象的属性是否需要操作或业务逻辑更改。例如,User或Person实例可能具有Password和LoginName->您的代码操作将根据其中的值进行更改。相反,如果您有Product,那么除了从db获取DataSet并构建GUI之外,您还要进行显示(仅此而已,没有其他动作)。
Yordan Georgiev

5
有一个平衡。避免宗教信仰,选择可行的方法。
杰夫·戴维斯

27

理论认为,高度凝聚力,松散耦合的实现是前进的道路。

因此,我想您正在质疑这种方法,即分离关注点。

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

在团队环境中,尤其是在您缺乏技术人员来处理应用程序的aspx部分的情况下,我不需要这些人能够“接触”这些东西。

将我的域与数据库分开可以保护我免受数据库结构性更改的影响,这肯定是件好事吗?确保数据库的有效性绝对重要,因此,让一位最擅长于此工作的人员可以在一处处理该工作,而对系统的其余部分的影响则尽可能小。

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

另外,您的方法似乎主张将应用程序的业务逻辑驻留在数据库中?我觉得这很不对劲,SQL确实擅长查询数据,而恕我直言,不能表达业务逻辑。

尽管有趣的想法,尽管感觉到与aspx中的SQL相距仅一步之遥,但与我过去糟糕的非结构化asp时代相比,这让我感到恐惧。


我同意,在整个代码背后散布大量动态SQL是邪恶的。您必须保持Db呼叫清晰明确。在静态辅助方法中包装sproc调用可实现某种分离,而无需一直沿ORM路线进行。
Eric Z Beard

1
尽管我从来没有在ASP环境中工作过,但是我敢肯定,一些技术水平较低的人会通过一些客户端javascript代码使您大吃一惊,无论技术支持者有多么卑鄙的界面,都可以带来出色的用户体验。 -结束。
Crowne 2010年

我在这里同意您的观点,并且我也做过一些客户端javascript,即使我自己也是这样,这也导致了不太糟糕的用户体验。我想认为后端接口并不是很糟糕,并且任何客户端程序员都不必担心这些,因为我试图将我的关注点分开。
nachojammers 2010年

2
“这对我来说是错的,SQL确实擅长查询数据,而恕我直言,不能表达业务逻辑。” -除非您使用PL / SQL,除非它在SQL之上(并与SQL紧密集成)添加了丰富的编程语言,并且您的代码存储在数据库中。通过避免网络往返来提高性能。并封装您的业务逻辑,而不管哪个客户端连接到数据库。
ObiWanKenobi 2010年

25

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

我要做的是使用“测试驱动开发”,因此我首先编写UI和Model层,然后对Data层进行模拟,因此UI和Model围绕领域特定对象构建,然后将这些对象映射到我正在使用的技术上数据层。让数据库结构确定应用程序的设计是一个坏主意。在可能的情况下,首先编写该应用程序,并让它影响数据库的结构,而不是相反。


9
我不得不说,我真的不同意,至少对于企业应用程序而言。数据就是应用程序。
Eric Z Beard

3
您为什么要具有相同数据的两个独立模型?
Seen Osewa

3
因为出于某些目的,对模型的一种解释可能更适合。在对象上,某些逻辑要比在行上更好。
Wouter Lievens

1
我认为这是个不好实施的好主意。
杰夫·戴维斯

21

对我来说,归结为我不希望我的应用程序关心数据的存储方式。我可能会因为这样说而被打耳光...但是您的应用程序不是您的数据,数据是应用程序的工件。我希望我的应用程序根据客户,订单和物料进行思考,而不是像DataSets,DataTables和DataRows ... cuz这样的技术,因为它们知道这些数据将持续多久。

我同意总会有一定程度的耦合,但是我更喜欢耦合向上而不是向下。比起改变树干,我可以更容易地调整其四肢和叶子。

我倾向于保留用于报告的存储过程,因为查询的确比应用程序的常规数据访问更难懂。

我也倾向于认为在这种情况下尽早进行适当的单元测试,就像不保留一列很可能不是问题。


3
“您的应用程序不是您的数据,数据是应用程序的构件。” -没有数据,应用程序一文不值。如果没有应用程序,数据将具有巨大的价值。应用程序总是来来往往(被重写),任何不重要的应用程序中的数据始终会保留。数据模型会随着时间的推移保持惊人的稳定。
ObiWanKenobi 2010年

16

埃里克,你死定了。对于任何真正可扩展/易于维护/健壮的应用程序,唯一的答案就是放弃所有垃圾并坚持基础知识。

我的职业生涯遵循相似的轨迹,并得出了相同的结论。当然,我们被认为是异端,但看上去很滑稽。但是我的东西行之有效。

每行代码都应引起怀疑。


2
肯定的是,它的确效果很好,当你得到吨人员anjd资源,但我认为,如果你是一个人的球队一想到“新”技术可以帮助很多..
卡尔·霍伯格

10

我想用一个与您提出的例子类似的例子来回答。

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

(在我看来)实体为项目带来的是:

正交性:一层中的更改可能不会影响其他层(当然,如果您对数据库进行较大的更改,它将在所有层中泛滥,但大多数较小的更改不会)。

可测试性:您可以在不接触数据库的情况下测试逻辑。这样可以提高测试性能(允许您更频繁地运行它们)。

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

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

干杯。


2
存储过程可能是正交性和关注点分离的最佳示例。如果使用正确,它们将完全封装数据库。
Eric Z Beard

1
@Eric Z Beard:是的,但是您如何在仅隔离存储过程中的逻辑的同时围绕存储过程编写单元测试?存储过程与datbase紧密耦合,我们大多数ORM类型都不喜欢。为了编写存储过程的单元测试,您将需要依赖数据库中的某些数据。如果没有数据依赖性,您将无法一遍又一遍地运行此测试。您编写的测试将不再是单元测试,而是集成测试。
09年

8

我认为您可能对此话题“咬牙切齿”。泰德·纽亚德(Ted Neward)称其为“ 计算机科学的越南 ”时,并没有表现出任何轻率。

我绝对可以保证的一件事是,它将改变任何人对此事的观点,这一点已在无数其他博客,论坛,播客等上得到了经常证明。

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

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


1
没错,大多数人不会改变意见。我意识到堆栈溢出的重点应该是客观问题,但是主观问题要有趣得多!就个人而言,我从这次讨论中学到了很多东西。
Eric Z Beard

我认为各种方法是特定于上下文的,并且该讨论可以消除歧义,哪些场景可以从不同的持久性模型中受益或从中受益。有关该主题的专家不会很快改变他们的看法,但这是一个人们寻求他人经验的问题站点。
TheXenocide

哇。+1是指向“越南计算机科学”文章的链接,该文章对ORM与非ORM进行了很好的介绍。
lambacck

7

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


哇,其他在我看来像我的人...我的应用几乎总是与数据操作有关,这就是他们的实际操作。
炼金术

既然现在可以提供这些功能,那么最好做个评论
Casebash 2010年

1
原谅我是个书呆子,但是由于这是一个很普遍的问题,而且您犯的错误是一个普遍的错误,所以我觉得应该指出这一点。“更少的时间”是正确的,但是“更少的人”和“更少的错误”应该是“更少的人”和“更少的错误”。如果面粉少,那么饼干也就少。(另外,如果您使用过多的面粉,那么您会做太多的曲奇,这是很少被忘记的区别。)再次,我道歉。只是想有所帮助。
WCWedin

4

我发现您的问题真的很有趣。
通常,我需要实体对象来封装应用程序的业务逻辑。将此逻辑推入数据层确实很复杂且不足。
您将如何避免这些实体对象?您有什么解决方案?


作为评论,这会更好
Casebash 2010年

4

实体对象可以促进在应用程序层上的缓存。祝你好运,缓存数据读取器。


4

我们还应该讨论实体实际上是什么的概念。当我通读此讨论时,我会感觉到,这里的大多数人都在从Anemic Domain Model的角度看待实体。许多人正在考虑将Anemic域模型用作反模式!

富域模型具有价值。这就是域驱动设计的全部意义。我个人认为OO是克服复杂性的一种方法。这不仅意味着技术复杂性(如数据访问,UI绑定,安全性...),而且还意味着业务领域中的复杂性

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

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

这是事实,数据的生活比应用更长的时间,但考虑到这句话大卫Laribee:模型是永远......数据是一个愉快的副作用。

有关此主题的更多链接:


1
坦率地说,我开始相信数据的寿命比其周围的软件更长,这是因为在真正理解业务的情况下,设计软件通常很少被关注。
flq

4

真有趣的问题。老实说,我不能证明为什么实体是好的。但是我可以分享我为什么喜欢他们的观点。像这样的代码

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

不必担心订单来自何处-从DB,从Web请求,从单元测试等。它使此方法更明确地声明其确切要求,而不是采用DataRow并记录其期望具有的列和它们应具有的类型是。如果您以某种方式将其实现为存储过程,则同样适用-您仍需要将记录id推送到该存储过程,而数据库中不必存在该ID。

该方法的实现将基于订单抽象,而不是基于数据库中的精确程度。我执行的大多数此类操作实际上并不取决于如何存储此数据。我确实了解到,出于性能和可伸缩性的目的,某些操作需要与数据库结构耦合,仅以我的经验来看,其中并没有太多。以我的经验,经常知道Person具有.getFirstName()返回String以及.getAddress()返回Address以及address具有.getZipCode()等是足够的,并且不必关心哪些表涉及存储该数据。

如果您必须处理所描述的问题,例如当其他列中断报告性能时,则DB对于您的任务至关重要,实际上您应该尽可能地接近它。虽然实体可以提供一些方便的抽象,但是它们也可以隐藏一些重要的细节。

可伸缩性在这里很有趣-大多数需要巨大可伸缩性的网站(例如facebook,livejournal,flickr)倾向于使用DB禁欲主义方法,这是因为尽可能少地使用DB,并且通过缓存(尤其是通过使用RAM)解决了可伸缩性问题。http://highscalability.com/上有一些有趣的文章。


2
企业应用程序中的可伸缩性通常无法通过缓存解决,因为太多的内容经常更改具有数百万行的表上的事务数据。我看到facebook等。等 作为高流量网站,其中最困难的部分是服务于如此多的Web请求。
Eric Z Beard

4

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

我不会考虑用sprocs + datareader代替好的ORM。使用存储过程时,您仍然受到过程类型签名的束缚,并与之紧密耦合,该过程使用与调用代码不同的类型系统。存储过程可以进行修改,以适应其他选项和架构更改。在架构可能发生更改的情况下,存储过程的替代方法是使用视图-您可以将对象映射到视图,然后在更改视图时将视图重新映射到基础表。

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

ADO.NET实体框架具有附加的优势,即您的数据库表可以看作是彼此继承的实体类,也可以看作是聚合到单个实体中的多个表的列。如果需要更改架构,则可以更改从概念模型到存储架构的映射,而无需更改实际的应用程序代码。同样,这里可以使用存储过程。

我认为,与应用程序的可伸缩性问题相比,企业中更多的IT项目失败是由于代码的不可维护性或开发人员生产力低下(这可能是由于在存储过程编写和应用程序编写之间进行上下文切换而引起的)。


我认为,将ORM映射到存储过程是一个很好的折衷方案,只是这样做很容易做起来很糟糕:如果仅为每个表创建4个CRUD proc,那么您将一事无成。您可以将大而粗粒度的proc映射到实体,还是不能真正带您到任何地方?
Eric Z Beard

除了CRUD操作之外,Microsoft ORM还允许您将方法添加到实体类上,这些方法直接映射到要向其抛出的任何存储proc(前提是所有输入/输出类型都是可映射的)。
马克·西达德

3

我还想补充一下Dan的答案,即分离两个模型可以使您的应用程序可以在不同的数据库服务器甚至数据库模型上运行。


3

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

但是,如果没有任何实体对象,那么它们就没什么好谈的了。

我并不是说,如果它是一个简单的,内部的,寿命短的应用程序,则不应编写整体。但是,一旦它变得相当复杂,或者应该持续大量的时间,您确实需要考虑一个好的设计。

这样可以节省维护时间。

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


3
许多人正在提出去耦,并允许改变一层而不影响另一层。存储过程比任何ORM都要好!我可以从根本上改变数据模型,只要过程返回相同的数据,任何操作都不会中断。
Eric Z Beard

2
我认为存储过程和实体模型不是互斥的。存储过程可以提供一种机制来存储您的实体模型。问题是:您的业务逻辑是与实体一起使用还是直接访问存储过程?
jbandi

3

您可能会在comp.object上发现这篇文章很有趣。

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


那是个很棒的帖子。几乎完美地总结了我对ORM的想法。
Eric Z Beard

3

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

在我感兴趣的企业应用程序类型中,我们必须处理多个站点,其中一些站点必须能够在断开状态下运行。
如果您的业务逻辑封装在可以轻松地集成到各种应用程序类型的域层中(比如说),dll那么我可以构建知道业务规则并能够在必要时将其应用于本地的应用程序。

为了将域层保留在数据库的存储过程中,您必须坚持使用一种需要永久访问数据库的应用程序。

可以在特定类别的环境中使用,但肯定不能涵盖企业应用程序的全部范围。


2

@jdecuyper,我经常对自己重复的一个格言是“如果您的业务逻辑不在数据库中,那只是一个建议”。我认为保罗·尼尔森(Paul Nielson)在他的一本书中曾说过这一点。应用程序层和UI来来往往,但是数据通常会生存很长时间。

如何避免实体对象?存储过程多为。我也自由地承认,无论您是否打算,业务逻辑都倾向于遍及应用程序的所有层。一定数量的耦合是固有的并且不可避免的。


我同意,仅应用程序中的业务逻辑常常无法说明可以输入,删除或更改数据的其他方式。这通常会导致数据完整性问题。
HLGEM,

以及为什么应该始终使用服务层来处理对象世界和关系世界之间的不匹配。毫无疑问,业务逻辑渗透到每一层都是不可避免的。
cdaq

2

最近我一直在想着同样的事情。我曾经是CSLA的重度用户,我很喜欢说“您的所有业务逻辑(或至少尽可能合理地封装在业务实体中)”的纯洁性。

我已经看到,在数据库的设计与您使用数据的方式不同的情况下,业务实体模型可以提供很多价值,在许多业务软件中都是如此。

例如,“客户”的概念可能由“客户”表中的主记录,客户已下达的所有订单以及所有客户的员工及其联系信息以及“客户”的某些属性组成可以从查找表中确定客户及其子级。从开发的角度来看,能够与Customer作为单个实体合作真的很不错,因为从业务角度来看,Customer的概念包含所有这些内容,并且关系可以在数据库中执行,也可以不执行。

尽管我赞赏“如果您的业务规则不在数据库中,这只是一个建议”的说法,但我也相信您不应该设计数据库来强制执行业务规则,而应该将其设计为高效,快速和规范化。

就是说,正如上面其他人提到的那样,没有“完美的设计”,该工具必须适合工作。但是,使用业务实体确实可以帮助维护和提高生产率,因为您知道去哪里可以修改业务逻辑,并且对象可以以直观的方式对实际概念进行建模。


2

埃里克,

没有人阻止您选择您想要的框架/方法。如果您要走“以数据驱动/存储过程为动力”的道路,那么一定要走!尤其是,如果确实能够帮助您按时按时交付应用程序。

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

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

这里唯一真正的规则是一致性一词。没有人阻止您以数据库为中心。没有人阻止您进行老式的结构化(又称功能/程序)程序。地狱,没人阻止任何人编写COBOL风格的代码。但是,如果应用程序希望获得任何程度的成功,那么它必须非常,非常一致。


我同意整个应用程序的一致性。坦白地说,我不久前就改变了当前项目的方向,却始终没有解决100%原始模型的问题,这让人感到困惑。最好早点做出正确的决定。
Eric Z Beard

埃里克(Eric),的确如此。我曾经是一个OOP狂热者(这个线程中的其他人似乎是这样),但是我遇到了一个拥有一家公司的人,该公司在销售DB驱动的应用程序方面非常成功。那震撼了我的世界。我仍然是一个OOP / TDD爱好者,但是我不再对以DB为中心的东西感到烦恼。
乔恩·利姆贾普

问题是,有时人们过度推销自己的意识形态,如果您有一个很好的方法将其淘汰,那么您就有可能靠出售html和javascript网站谋生。
Mark Rogers 2009年

2

我真的不确定您认为“企业应用程序”是什么。但是我给您的印象是,您将其定义为内部应用程序,其中RDBMS可以固定使用,并且该系统不必与任何其他系统(内部或外部)都可以互操作。

但是,如果您有一个数据库,其中包含100个表,每个表仅相当于4个存储过程,仅用于基本的CRUD操作,则需要维护400个存储过程,这些存储过程不是强类型的,因此容易出现拼写错误,也无法进行单元测试。当您获得一位新的CTO(即一位开源传道者)并想要将RDBMS从SQL Server更改为MySql时,会发生什么?

如今,无论企业应用程序还是产品,许多软件都在使用SOA,并且对公开Web服务有一些要求,至少我本人并且曾经参与其中。使用您的方法,最终会暴露出序列化的DataTable或DataRows。现在,如果保证客户端是.NET并在内部网络上,则这可以视为可接受。但是,如果不知道客户端,那么您应该努力设计一种直观的API,并且在大多数情况下,您不希望公开完整数据库模式。我当然不想向Java开发人员解释DataTable是什么以及如何使用它。还需要考虑带宽和有效负载大小以及序列化的数据表,因此数据集非常繁重。

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

只是我的2美分


不,我对企业应用程序的定义是相反的。模式经常更改,并且有许多使用db的应用程序,并且它可以与许多外部合作伙伴进行互操作。在真正的企业应用程序中,您永远都不会更改为其他RDBMS。只是没有发生。
Eric Z Beard

为每个表创建4个proc是一个不好的做法。它将您紧密地耦合到数据模型,就像从ORM中生成的sql一样,因此您一无所获。proc需要是粗粒度的业务操作,而不仅仅是每个表上的CRUD。
Eric Z Beard

但这不是答案吗?:您需要编写的代码越多,就需要更多的大规模编程支持功能:封装,字符串键入,重构,复杂的样式和错误检查等;Java和.NET在这方面有很多支持,而存储过程语言则没有。
reinierpost

2

我想为OO和RDB之间的距离问题提供另一个角度:历史。

任何软件都具有现实模型,在某种程度上是现实的抽象。没有计算机程序可以捕获现实的所有复杂性,而编写程序只是为了解决现实中的一系列问题。因此,任何软件模型都是现实的缩影。有时,软件模型会迫使现实降低自身。就像您想让汽车租赁公司为您保留任何一辆汽车,只要它是蓝色且有合金的汽车一样,但由于您的请求不适合计算机,因此操作员无法遵守。

RDB源自将信息放入表格的一种非常古老的传统,称为会计。记帐是在纸上完成的,然后是打孔卡,然后是计算机。但是会计已经成为现实。会计一直迫使人们遵循其制度,直到它成为公认的现实。这就是为什么制作用于会计的计算机软件相对容易的原因,因为会计早在计算机问世之前就有其信息模型。

鉴于良好的会计系统的重要性以及您得到任何业务经理的认可,这些系统已经变得非常先进。现在,数据库的基础非常牢固,并且毫不犹豫地将重要数据保存在如此值得信赖的环境中。

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

我们中的许多人都想使用OO,但我们仍然希望安全地存储数据。有什么比像尊敬的会计系统一样存储我们的数据更安全的呢?这是一个诱人的前景,但我们都遇到了同样的陷阱。与RDB行业做出巨大努力相比,很少有人会想到OO持久性,RDB行业已经受益于会计的传统和职位。

Prevayler和db4o是一些建议,我敢肯定还有其他一些我没听说过的建议,但是似乎没有任何一个可以说是冬眠了。

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

在我为消除OO和RDB之间的鸿沟所做的日常努力中,我尽可能地使用OO,但要尽量减少继承。我不经常使用SP。我只会在看起来像会计的方面使用高级查询内容。

鸿沟永远关闭时,我会感到惊讶。我认为该解决方案将在Oracle启动“ Oracle对象实例库”之类的东西时出现。要真正流行起来,它必须有一个令人放心的名称。


我认为您不需要面向对象的ORM被认为有用。我使用存储的proc并在我的代码中编写了许多静态帮助器类,但是这些类是基于庞大的.NET框架构建的,该框架是对象的绝妙集合。
Eric Z Beard

您的逻辑是有道理的,但我认为前提不是合理的。我从未听说过RDB无法映射的任何内容。
杰夫·戴维斯

1

目前时间不多,但就在我的头顶上。

实体模型使您可以为数据库(和其他可能的系统)提供一致的接口,甚至可以超出存储过程接口可以提供的接口。通过使用企业范围的业务模型,您可以确保所有应用程序一致地影响数据,这是非常重要的。否则,您将获得错误的数据,这简直就是邪恶。

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

不过,您应该牢记以下几点(IMO):

  1. 生成的SQL代码不好(要遵循的例外)。抱歉,我知道很多人认为这可以节省大量时间,但是我从来没有发现能够产生比我编写的代码更有效的代码的系统,并且通常这些代码简直太恐怖了。您通常还会最终生成大量从未使用过的SQL代码。这里的例外是非常简单的模式,例如查找表。虽然很多人对此感到迷惑。
  2. 实体<>表(甚至必须是逻辑数据模型实体)。数据模型通常具有应与数据库尽可能紧密地实施的数据规则,其中可以包括有关表行如何相互关联的规则,或者对于声明性RI而言过于复杂的其他类似规则。这些应在存储过程中处理。如果所有存储过程都是简单的CRUD proc,那么您将无法做到这一点。最重要的是,CRUD模型通常会造成性能问题,因为它无法最大程度地减少网络与数据库之间的往返路程。这通常是企业应用程序中最大的瓶颈。

同意生成的SQL。它总是会带来更多无法解决的问题。我非常反对仅使用存储的proc创建CRUD层。进程应尽可能地粗糙。不确定如何定义“一个应用程序”。
Eric Z Beard

我所说的一个应用程序是指由组织中的单个小组编写的单个应用程序。我现在正在咨询的地方有一个公司数据库,至少三个独立的小组可以访问这些数据库,这些小组处理三个不同的应用程序,并且它们之间的通信有限。
汤姆H”

1

有时,您的应用程序和数据层并没有那么紧密地耦合在一起。例如,您可能有一个电话计费应用程序。稍后,您将创建一个单独的应用程序,以监视电话使用情况,以便a)更好地向您宣传b)优化您的电话计划。

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


1

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

您几乎卡在了数据库中,如果您对对当前数据库系统感到满意的公司,这也不错。但是,由于数据库会随着时间的推移而发展,因此可能会出现一个新的数据库系统,该数据库系统确实非常整洁,可以供贵公司使用。如果他们想切换到Web服务的数据访问方法怎么办(就像有时面向服务的体系结构那样)。您可能必须在各处移植存储过程。

此外,域逻辑还会抽象出UI,这在具有不断发展的UI的大型复杂系统中(尤其是当他们不断寻找更多客户时)尤其重要。

同样,尽管我同意对存储过程和域逻辑的问题没有明确的答案。我正处于领域逻辑阵营中(并且我认为它们会随着时间的流逝而获胜),因为我相信,精心设计的存储过程比精心设计的领域逻辑更难维护。但这是另一场辩论


0

我认为您只是习惯于编写特定类型的应用程序并解决特定类型的问题。您似乎从“数据库优先”的角度进行攻击。有很多开发人员可以将数据持久存储到数据库中,但是性能并不是重中之重。在很多情况下,将抽象放在持久层上可以大大简化代码,而性能成本却不是问题。

无论您做什么,都不是OOP。没错,这不是面向对象的,将解决方案应用于所有其他问题也没有意义。


数据永远是第一位的。这是您首先拥有计算机程序的原因。因此,“数据库优先”可能是设计应用程序的唯一有效方法。
gbjbaanb

0

有趣的问题。一些想法:

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

0

好问题!

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

例如,

AnswerIterator对象生成AnswerIterator.Answer对象。在后台,它遍历一个SQL语句以获取所有答案,并遍历另一个SQL语句以获取所有相关注释。但是,当使用迭代器时,我只使用在此上下文中具有最少属性的Answer对象。有了一些基本代码,这几乎变得微不足道了。

我发现,当我有一个庞大的数据集需要处理时,这种方法就很好用,而且如果正确完成,它可以为我提供相对较小的临时对象,这些对象相对易于测试。

从本质上讲,它只是数据库访问方面的薄板,但仍为我提供了在需要时对其进行抽象的灵活性。


0

我的应用程序中的对象倾向于与数据库一对一关联,但是我发现使用Linq To Sql而不是sprocs可以使编写复杂查询变得更加容易,尤其是能够使用延迟执行来构建它们。例如,从Images.User.Ratings中的r中获取r等,这省去了我尝试在sql中计算多个join语句的麻烦,而使用Skip&Take进行分页也简化了代码,而不必嵌入row_number和“ over”代码。


用这种方式做事存在很大的危险。最后,大多数复杂的查询最终都需要由DBA完全重写才能使其扩展。索引调整有时无济于事。这种类型的Linq2Sql耦合非常紧密。
Eric Z Beard

0

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


我不认为OO是“绒毛”。仅仅在过去十年左右的时间里,MSFT,Sun等已经编写了我们将永远需要的99%的对象。仅仅因为我在框架之上编写了许多静态类,并不意味着我没有使用OO。
Eric Z Beard
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.