没有ORM的后端
#typescript #database #orm #backend

关于ORM的几句话

ORM(对象依赖映射)是一种编程技术,可让您从外部存储(例如数据库)将数据映射到本地编程对象。
这种方法使开发人员可以从数据库特异性中抽象,并作为常见函数调用执行CRUD操作。这是有益的,因为我们不必知道实际的数据库语法,因此某些ORM甚至可以同时在SQL和NOSQL数据库上工作。
但是本文的标题没有说“为什么每个人都应该总是Orms”,因此我想指出ORM的缺点并提出另一种方法。

为什么您不需要ORM

与数据库的通信

数据库数据的最低级别表示形式是纯字节(如果我们一直向下移动,它实际上是在电线和半导体中存储并移动的电子,但我们将留在软件字段中)。因此,当任何驱动程序通过网络与实际数据库对话时,它会发送并接收字节包。此外,基于数据库协议,该协议描述了如何读取和处理这些字节,驱动程序将字节转换为有意义的数据结构。因此,正如我们所看到的,数据库驱动程序在这里像ORM一样工作:它将原始数据映射到您的编程语言构造中。 ORM将这些数据进一步映射到不同的构造中。从驱动程序接收到的数据已准备好在您的应用程序中使用。这是您为什么不需要ORM的第一点。

原始数据功能强大

因此,您可以从数据库中读取一些数据,然后获得数组(或列表,序列,或迭代器,具体取决于您的语言和选择的驱动程序)。盒子的权利,您可以使用强大的工具来使用该数据,因为您的标准库包含许多在数组和地图上起作用的功能。相反,这些功能可能在特定于ORM的对象上起作用。此外,原始数据是完全可序列化的,可以通过电线传输。

您的ORM支持测试吗

为与存储数据一起使用的实体编写单元测试时,理想情况下,您想对数据库层一无所知。原始数据与本质上的起源是分离的,可以按照您的喜好进行模拟。
另一方面,ORM取决于其实现,可能支持某些模拟存储,否则,您必须始终在某些数据库前执行测试。

ORM图书馆作者不知道您的域

但是你这样做。有时,更具体的解决方案可能对您的项目有益。也许对生成的SQL有一些增加,可以极大地提高查询速度。

数据库可能很复杂

超越简单的CRUD操作数据库可以支持许多惊人的功能,例如碎片,不同的索引类型,非标准的条件操作员和非标准的内置功能。大概一个ORM库缺乏对您正在使用的数据库的许多功能的支持。
另外,如果您选择一个ORM库并以此为基础,则您将自己与该库纽带,在某个时候,如果有一个数据库解决方案可能对您的应用程序域有益,则最终可能会遇到需要的情况。大规模刷新您的代码库。

里奇说奥姆很糟糕

认真的,如果您还没有看过Rich Hickey的"Simple made easy"演讲,请帮自己一个忙,这是非常启发的。

如何在没有ORM的情况下建造

让我们弄清楚如何使用“否ORM”方法来构建我们的项目。我们想构建一个可与数据库分开测试的解决方案,在数据上运行,并具有定义明确的边界的层(Uncle Bob的kudos)。
我将使用节点,打字稿和霓虹灯(Postgres)构建一个示例。它将包含一个单个实体-User,带有属性nameage

型号

那么我们如何代表概念中的模型?这只是一个接口!
link

export type User = {
  id: number;
  name: string;
  age: number;
};

如果以后我们要添加一些在User上操作的方法,那么我们只编写一个接受User作为参数或返回User形状对象的函数。
现在,我们要将User实体连接到数据库:将其存储,检索,修改和删除。

存储库层

现在让我们添加实体Repository。它将具有在原始数据上运行并执行数据库操作的CRUD方法。
link

export type Repository<T extends Record<string, any>> = {
  name(): string;
  create(data: Omit<T, "id">): Promise<T>;
  readMany<K extends keyof T>(filters: Filter<T, K>[]): Promise<T[]>;
  read(id: string): Promise<T>;
  update(id: string, data: T): Promise<T>;
  delete(id: string): Promise<T>;
};

Repository是我们缺少的数据库操作层。它可以执行所有“获取,存储数据”的内容。另外,如果某些实体需要其他操作,我们可以通过createOrReplaceupdateMany等其他操作扩展基本的Repository

数据库适配器

数据库适配器将是返回Repository实例的函数。这是如何查找Postgres数据库的示例。 link

如果我们想测试适配器,我们可能会以快照的方式对真实数据库进行操作:

  • 使用测试适配器创建一个测试存储库
  • 运行一些方法
  • 检查数据库状态是否与我们的期望匹配

link

我们的存储库非常有用

实际上,我们的存储库实例不仅对数据库管理有益。例如,我们可以从中构建REST API。 link
并为该实现编写测试。 link

结论

我要诚实

很合理,ORM的当前状态并不像以前那么糟糕。有像Prisma这样的现代框架,可以承认我上面描述的一些问题。
例如,Prisma生成一个客户端,该客户端在使用内置查询方法时返回仅键入数据,因此它被设计解耦。
我会说,当您可以将数据库框架视为高级驱动程序时,这是一个好兆头。
尽管如此,使用Prisma还是很难迁移到不支持的数据库,因此您需要牢记这一点。

TL;

可能我想传达的主要想法是:提前和提前思考的应用程序层。而且,由于几乎不可能预测您的应用程序应在五年,两年或一年内提供的功能,因此您需要创建一个非常灵活的体系结构,并且从我所知道的范围内,使用明确的界限将设计分层是最好的方法。