你为什么会使用 ORM?

发布: (2025年12月3日 GMT+8 19:50)
9 min read
原文: Dev.to

Source: Dev.to

Cover image for Why would you ever use an ORM?

软件开发始终是在多个方面之间寻找平衡:开发速度(你多快能够交付新功能)、应用性能、内存消耗、UI 质量以及业务逻辑的整洁度。

在大多数情况下,开发速度比性能或内存消耗更重要。性能往往是“足够好”,内存使用往往是“可接受”,但开发速度直接影响业务盈利。开发速度永远不会“太多”——它决定了企业在构建产品上要花多少钱,以及在风险压力下能坚持多久。如果你面向的是竞争激烈的市场,而竞争对手能够更早上线,那么没有什么比这更关键的了。

当然,几乎不动的应用或消耗荒唐内存的应用是无法在竞争中生存的。但如果把提升 20% 的应用速度和节省两三个月的开发时间进行比较,选择显而易见。用户可能感觉不到额外的 20% 加速,但预算缺口肯定会被注意到。

ORM 如何加速开发

ORM 是一种旨在节省开发时间的工具。但具体是怎么做到的呢?

  • 更短的代码 – 它隐藏了在表列与类字段之间搬运数值所需的样板代码。这也保证了类型安全:类字段的类型始终与数据库列的类型匹配。
  • IDE 支持 – 自动补全在任何地方都能工作,提升开发者体验和代码正确性,从而加快工作速度。
  • 降低认知负担 – 更短、更易读的代码写起来更快,也更容易理解,尤其在大型项目中,人脑的容量往往是限制因素。
  • 更高层次的抽象 – ORM 暴露的是对象而不是原始字段。你可以使用多态对通用的基础查询进行修改,以适配多个具体场景,或根据用户输入动态添加条件。用原始 SQL 实现同样的功能要困难得多。
  • 更少的错误 – 手写 SQL 时,几十个字段中出现错误很容易。ORM 不会出现这种错误,并且在你添加或重命名字段时会自动更新所有查询,消除一整类人为错误,节省大量调试时间。
  • 简化重构 – 使用 ORM 清理和重组模式要容易得多。模式重构可以让长期开发的效率提升一个数量级。

是的,新抽象层会带来一些入门复杂度。如果你的项目只有十张表且几乎不变,可能根本不需要 ORM。ORM 的存在是为了解决高复杂度的问题,而小项目根本没有这种复杂度。

对性能的影响

前面说过,开发是一场妥协的搜索。使用 ORM 就意味着性能下降或内存使用增加吗?不一定。

  • ORM 在构建查询和映射数据时会有一些开销,但相对于数据库 I/O,这种开销可以忽略不计。
  • 更短的代码和更容易的算法优化往往让基于 ORM 的逻辑在长期来看比原始 SQL 更快。原始 SQL 可以被优化,但很难看到全局图景,开发者也常常因为害怕破坏已有功能而不愿动手。
  • 悖论 – 原始 SQL 在首次编写时可能稍快,但经过多次迭代后,ORM 版本往往因增量清理和更安全的重构而显著更快。

有人认为 ORM 让生成过多查询变得太容易,尤其是那些不懂 SQL 的初级开发者。事实很简单:要正确使用 ORM,你必须了解 SQL。你需要明白你的语言层表达式会生成什么样的 SQL。ORM 并不是 SQL 的替代品;它是位于 SQL 之上的抽象层。

内存消耗

内存消耗同样不是单纯的概念。

// Example: a DataTable row may occupy far more memory than a simple typed field
Int32 value; // occupies 4 bytes (plus possible overhead in managed environments)

我见过开发者把整张表加载到 DataTable 对象中,然后像操作 Excel 表一样使用它们。在这种结构里,一个 Int32 可能在栈上占用 8 字节,在堆上再占用 24 字节(CLR,x64)。ORM 将数据存放在强类型字段中,能够大幅降低内存使用。

数据库查询结果本质上是扁平表。想象一张拥有 100 多列(例如 orders)的表与一张拥有 5 个字段的表(positions)进行一对多关联。如果把结果“原样”存储,每条 positions 记录都会复制左表的全部 100 多个字段。内存浪费可能会达到十倍甚至百倍。好的 ORM 会把子行聚合到单个父实例下,而不是复制所有数据。

模式同步

任何 ORM 的首要任务都是保持数据库模式与应用对象的同步。这就是映射的本质:把表列加载到类字段并写回。要做到这一点,ORM 必须在编译时获取“原始”模式定义。该定义可以来自数据库(db‑first)、来自代码(code‑first)或来自独立模型(model‑first)。

  • Code‑first 将模式从代码投射到数据库。当你有多个环境时很方便,但当多个独立服务试图各自重塑数据库时就会出现问题。同步变得复杂,因为它需要加载已有模式、正确比较并生成复杂的 DDL。
  • DB‑firstmodel‑first 依赖实体类的代码生成。这样更简单:从数据库(或模型文件)加载模式并重新生成实体文件。

在实际使用中,模式同步总会有项目特定的需求。你可能需要为自定义规则扩展生成器(例如把数据库注释导入实体文件、通过文本列处理多对多关联、或使用自定义逻辑映射枚举)。内置的 ORM 生成器往往是封闭的,难以自定义。

ORM 的一个常见批评就是这种僵硬。一个解决方案是使用开源生成器。例如,MIT 许可证的 OrmFactory 可以根据你的项目需求进行修改。它直接与数据库交互,并能把模式导出到项目中,处理模式设计和同步,而让 ORM 专注于它最擅长的——映射。

Back to Blog

相关文章

阅读更多 »

Bf-Trees:突破页面壁垒

你好,我是Maneshwar。我正在开发FreeDevTools——一个在线的开源中心,将 dev tools、cheat codes 和 TLDR 汇集在一个地方,方便……