对于支持数据验证的ORM,是否也应在数据库中强制执行约束?


13

除了(ActiveRecord)模型外,我还始终在数据库级别应用约束。但是我一直在想这是否真的必要吗?

一点背景

最近,我不得不对模型的基本自动时间戳生成方法进行单元测试。通常,测试会创建模型的实例并保存而不进行验证。但是表定义中还有其他必填字段不能为空,这意味着即使我跳过ActiveRecord验证,也无法保存实例。因此,我在考虑是否应该从数据库本身中删除此类约束,并让ORM处理它们?

如果我跳过db,imo中的约束,可能的优点 -

  • 可以修改模型中的验证规则,而不必迁移数据库。
  • 可以跳过测试中的验证。

可能的缺点?

如果可能ORM验证失败或被旁路,则数据库不会检查约束。

你怎么看?

编辑在这种情况下,我使用的是Yii Framework,它从数据库生成模型,因此也生成了数据库规则(尽管我总是可以自己在生成后编写它们)。


3
如果可以不使用您的ORM(其他没有您的ORM的应用程序,或者更糟糕的是,用户直接进行数据库访问)来常规地修改数据库中的数据,则确实需要在数据库中进行验证。
Marjan Venema 2012年

Answers:


16

您的指导原则应该是“ 不要重复自己”

在软件工程中,“不要重蹈覆辙”(DRY)是一种软件开发原则,旨在减少各种信息的重复,这在多层体系结构中特别有用。DRY原则被声明为“系统中的每条知识都必须具有单一,明确,权威的表示形式”。

ORM本质上是一个额外的层(或者,如果您愿意,可以是一层),位于您的应用程序和数据存储之间。您的约束应该放在一个位置,也只能放在一个位置,无论是ORM 还是数据存储,否则很快您将最终维护它们的不同版本。您真的不想这样做。

但是,实际上,大多数像样的ORM会根据数据模式自动生成大量模型。尽管仍然存在重复,但是由于每次重复的ORM代码都是按照相同的模式生成的,因此发生地狱的机会很小。没有重复的代码将是理想的选择,但是自动生成的约束是下一个优点。

同样,将约束放在一个地方并不一定意味着您应该将所有约束都放在同一个地方。有些,例如参照完整性约束,可能更适合于数据存储(但是如果您移至另一个数据存储,则可能会丢失),而有些(大多数是关于复杂业务逻辑的)更适合您的ORM。最好将所有苹果放在同一个篮子里,但是…

失败的

您提到ORM失败。这与您的问题绝对无关,您的应用程序应该将ORM和数据存储视为一个整体。如果失败,则失败,绕过ORM直接与数据存储通信不是一个好主意。

绕过ORM进行其他任何操作

也不是一个好主意。但是,它可能由于多种原因而发生:

  1. 引入ORM之前构建的应用程序的旧部分。

    这是一个艰难的一个,正好和与我打交道的情况,现在,“维护地狱”的,因此我不断重复。您要么继续维护非ORM部分,要么重写它们以使用ORM。第二种选择一开始可能更有意义,但这是一个决定,它完全取决于应用程序的那些部分到底在做什么,以及从长远来看,完全重写的价值。

    尝试在设计错误的2 * 10 ^ 8行MySQL表中更改键(无停机),您将了解我的来历。

  2. 绝对需要直接与数据存储通信的应用程序的非遗留部分:

    甚至更棘手。ORM是精美的工具,它们几乎可以处理所有事情,但有时它们会妨碍您甚至是完全没有用。流行语(实际上是流行语)是对象关系阻抗不匹配,简单地说,从技术上讲,您的ORM不可能完成关系数据库所做的一切,而且对于它们所做的某些事情,这会严重影响性能。

注释

从数据完整性的角度来看,约束必须在数据库上,而应该在应用程序上。如果从Web和桌面应用程序,移动应用程序或Web服务访问您的应用程序怎么办?– 路易斯·达米姆Luiz Damim)

这是在其中添加额外的层将非常有帮助的地方,并且如果我们谈论的是Web应用程序,则我将使用REST API。一个过于简单化的设计,因为这将是:

在此处输入图片说明

ORM将位于API和数据存储之间,并且API(包括它)后面的所有内容都将被视为来自各种应用程序的单个实体。


通常,您将在ORM中定义一个架构,然后将其镜像到数据库中,以便获得第二级保证。
2012年

2
@JoshK您说第二级保证,我说维护地狱。并不是说你不对……
yannis 2012年

说得通。我正在遵循这条路线。谢谢!
2012年

1
一旦超过一两个开发人员执行代码数据库工作的地步,这将成为必然的恶魔。如果您使用好的ORM,它也会为您生成迁移。当您成长为拥有专用DBA时,没有办法解决,他们不会让表无约束地浮动。阻止人们注册而没有电子邮件的简单方法是对其进行存储级别限制。
2012年

1
从数据完整性的角度来看,约束必须在数据库上,而应该在应用程序上。如果从Web和桌面应用程序,移动应用程序或Web服务访问您的应用程序怎么办?
Luiz Damim 2012年

20

这实际上是一个很难回答的问题,我发现这是一个很有争议的话题。

正如Yannis Rizos在他的回答中指出的那样,在数据库和ORM层具有约束逻辑似乎违反了DRY,这“可能导致维护方面的噩梦,不良的分解以及逻辑上的矛盾”。

但是,如果满足以下任一条件,则从数据库中删除约束逻辑并将其保留在ORM层将不起作用:

  1. 手动数据库更新(似乎在每个公司中都发生)

  2. 来自不能总是轻松共享ORM约束逻辑的另一个系统的数据库更新(例如,在Hibernate中实现ORM层并由Java应用程序用于日常活动时执行例行任务的Perl脚本)

这将建议您仅将约束逻辑添加到DB并从ORM层删除,以防止违反DRY。但是,这可能导致应用程序代码无法成功捕获实际问题并传递给用户的情况(尽管作为开发人员调试问题,您很有可能可以做到)。对于某些项目,这可能是不可接受的。

您的最后一个选择是根据数据库约束自动在ORM(和任何其他系统)中创建约束(反之亦然)。尽管您最终将获得约束的两个或多个实现,但这并不会违反“实用程序”中描述的DRY原理,因为他们建议使用代码生成以避免DRY违反。当然,它不是那么简单,因为,例如,对数据库约束的每次更改都可能会强制重新构建和重新部署使用该约束的所有应用程序(自动化并非易事)。

确实,必须逐案评估。我可以告诉你,到此为止,当我建议不要重复约束逻辑时,我总是茫然无措。


2
刚下班,就在考虑将我的答案扩大为您刚刚发布的内容。好答案!
yannis 2012年

3

我肯定会将约束添加到数据库中作为默认选项。这是因为对于企业而言,数据为王,而数据质量是最重要的。@Yannis Rizos将DRY原理引入了讨论。另一个原则是深度防御。对于数据,我将使用此原理。

我曾在数据库拥有30年前创建的数据的真实企业中工作。COBOL应用程序曾经(现在)仍然可以访问它,现在.Net应用程序可以访问它。谁知道,在10年内它可能是供应商应用程序。发生了合并,并且使用SQL将数百万行的数据转换并从另一公司迁移到该数据库。没有ORM可以做到这一点。底线是数据保留,应用程序更改,数据生成方式更改。那么为什么不减少数据损坏的机会呢?


2

我认为你们都在某种程度上做到了。

  • 主要的约束应该存在于ORM中-编程语言要灵活得多,当需求改变时,它更易于测试和调整。至少不必担心DDL修复程序。而且通常可以避免难以测试的数据回归问题。

  • 数据库中还应包含一些非常严格的约束。例如,我不是在谈论非空名称。我说的是诸如引用完整性之类的东西,或者需要一些绝对关键的标识符。结构上的要求,因此您的代码无需处理“如果订单不存在该怎么办”。


1

数据库是IMO唯一可能违反DRY的地方,因为如果某些内容绕过了您的ORM并有不良数据,就是这样。游戏结束。拥有损坏的数据是致命的打击。


仅数据库?我可以想到许多情况,即使根本没有持久性,与数据相关的行为也应该存在于多个层(逻辑或物理)上。有时可能只有一个源代码,并且可以减少对已部署dll的“重复”。
mike30 2012年
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.