TypeORM:在运行时动态设置EntityManager或存储库的数据库架构?

B12*_*ter 6 postgresql orm multi-tenant typeorm nestjs

情况:

对于我们的SaaS API,我们使用基于架构的多租户,这意味着每个客户(〜租户)在同一个(postgres)数据库中都有自己独立的架构,而不会干扰其他客户。每个模式都包含相同的基础实体模型。

每次向系统注册新客户时,都会在数据库中自动创建一个新的隔离模式。这意味着该架构是在运行时创建的,并且事先未知。客户的架构是根据客户的域命名的。

对于到达我们API的每个请求,我们从JWT中提取用户的租约关联,并确定使用哪个db模式来为此租户执行请求的db操作。

问题

通过TypeORM(例如,使用createConnection)建立与(postgres)数据库的连接之后,我们为db-operation设置架构的唯一机会是诉诸于createQueryBuilder

const orders = await this.entityManager
  .createQueryBuilder()
  .select()
  .from(`${tenantId}.orders`, 'order') // <--- setting schema-prefix here
  .where("order.priority = 4")
  .getMany();
Run Code Online (Sandbox Code Playgroud)

这意味着,我们不得不使用,QueryBuilder因为在使用EntityManager API(或Repository API)时似乎无法设置架构。

但是,我们希望/需要使用这些API,因为它们更容易编写,需要更少的代码并且也不容易出错,因为它们不依赖于使用基于字符串的语法“手动”编写查询。

如果是TypeORM,在使用EntityManager或存储库时是否可以通过某种方式设置db模式?

像这样吗

// set schema when instantiating manager
const manager = connection.createEntityManager({ schema: tenantDomain });

// should find all matching "order" entities within schema
const orders = manager.find(Order, { priority: 4 })

// should find a matching "item" entity within schema using same manager
const item = manager.findOne(Item, { id: 321 })
Run Code Online (Sandbox Code Playgroud)

笔记:

  • 需要以请求范围的方式设置db模式,以避免为其他请求(可能属于其他客户)设置模式。不能为整个连接设置模式。
  • 我们知道可以创建一个全新的连接并设置该连接的架构,但是我们想重用现有的连接。因此,简单地创建一个新连接来设置架构不是一个选择。

B12*_*ter 15

回答我自己的问题:

目前没有办法在运行时实例化具有不同模式的TypeORM 存储库而不创建新连接。

因此,对于基于架构的多租户,开发人员仅有的两个选择是:

  1. 设置新连接以在运行时连接同一数据库中的不同模式。例如,请参阅多数据库的 NestJS 请求范围多租户。但是,绝对应该努力重用连接并注意连接限制
  2. 放弃使用RepositoryApi并恢复使用createQueryBuilder(或通过 执行 SQL 查询query())的想法。

为了进一步研究,这里有一些 TypeORM GitHub 问题,它们跟踪在运行时更改现有连接或存储库的架构的想法(类似于 OP 中的请求):

PS 如果 TypeORM 决定支持 OP 中讨论的想法,我将尝试更新此答案。