在我的大多数项目中使用Hibernate大约8年之后,我进入了一家不鼓励使用Hibernate并希望应用程序仅通过存储过程与DB进行交互的公司。
在执行了几周之后,我无法为我将开始构建的应用程序创建丰富的域模型,并且该应用程序看起来像(可怕的)事务脚本。
我发现的一些问题是:
- 由于存储过程仅加载最少的数据,因此无法导航对象图,这意味着有时我们具有具有不同字段的相似对象。一个示例是:我们有一个存储过程来从客户那里检索所有数据,另一个存储过程是从客户那里检索帐户信息以及一些字段。
- 许多逻辑最终出现在帮助器类中,因此代码变得更加结构化(实体用作旧的C结构)。
- 令人讨厌的脚手架代码,因为没有框架可以从存储过程中提取结果集并将其放入实体中。
我的问题是:
- 有没有人遇到过类似情况,并且不同意存储过程方法?你做了什么?
- 使用存储过程有实际好处吗?除了“没有人可以发布弃用表”这一愚蠢的观点之外。
- 有没有一种使用存储过程来创建富域的方法?我知道有可能使用AOP将DAO /存储库注入到实体中,从而能够导航对象图。我不喜欢这个选项,因为它非常接近伏都教。
结论
首先,谢谢大家的回答。我得出的结论是,ORM无法启用Rich Domain模型的创建(如某些人所述),但是它确实简化了(通常是重复的)工作量。以下是对结论的更详细说明,但并不基于任何硬数据。
大多数应用程序请求并将信息发送到其他系统。为此,我们在模型术语(例如,业务事件)中创建抽象,然后域模型发送或接收事件。事件通常需要来自模型的一小部分信息,而不是整个模型。例如,在一家网上商店中,支付网关会向用户收取一些用户信息和总计费用,但不需要购买历史记录,可用产品和所有客户群。因此,该事件具有少量特定的数据集。
如果我们将应用程序的数据库作为外部系统,则需要创建一个抽象,以允许我们将域模型实体映射到数据库(如NimChimpsky所述,使用数据映射器)。明显的区别是,现在我们需要为每个模型实体手工映射到数据库(旧模式或存储过程),而且还有一个痛苦,因为两个实体不同步,所以一个域实体可能会部分映射数据库实体(例如,仅包含用户名和密码的UserCredentials类映射到具有其他列的Users表),或者一个域模型实体可能映射到多个数据库实体(例如,如果存在一对一一张表上的映射,但我们只想将所有数据归为一类)。
在只有几个实体的应用程序中,如果不需要横向实体,那么额外的工作量可能很小,但是当有条件需要横向实体时,额外的工作量就会增加(因此,我们可能想实现某种“懒惰”正在加载”)。随着应用程序具有更多实体的发展,这项工作只会增加(我感觉它会非线性地增加)。我在这里的假设是,我们不会尝试重塑ORM。
将数据库视为外部系统的一个好处是,我们可以围绕以下情况编写代码:需要运行两种不同版本的应用程序,其中每个应用程序都有不同的映射。在连续交付生产的情况下,这变得更加有趣……但是我认为ORM在较小程度上也是可行的。
我将不考虑安全性,因为开发人员即使没有访问数据库的权限,也可以通过注入恶意代码来获取存储在系统中的大部分(即使不是全部)信息。我不敢相信我忘了删除记录客户信用卡详细信息的行,亲爱的上帝!)。
小更新(6/6/2012)
存储过程(至少在Oracle中)阻止执行诸如零停机时间连续交付之类的操作,因为对表结构的任何更改都将使过程和触发器无效。因此,在更新数据库期间,应用程序也将关闭。Oracle 为这种称为基于版本的重新定义提供了解决方案,但是我向该功能询问过的少数DBA提到,该功能实施得很差,他们不会将其放入生产数据库中。