web-dev-qa-db-fra.com

TypeORM: schéma de base de données défini dynamiquement pour EntityManager ou les référentiels lors de l'exécution?

Situation:

Pour notre SaaS nous utilisons multitenancy basé sur un schéma , ce qui signifie que chaque client (~ locataire) a son propre schéma dans le même (postgres), sans interférer avec les autres clients. Chaque schéma se compose du même modèle d'entité sous-jacent.

Chaque fois qu'un nouveau client est enregistré sur le système, un nouveau schéma isolé est automatiquement créé dans la base de données. Cela signifie que le schéma est créé au moment de l'exécution et n'est pas connu à l'avance. Le schéma du client est nommé en fonction du domaine du client.

Pour chaque demande qui parvient à notre API, nous extrayons l'affiliation de location de l'utilisateur du JWT et déterminons le schéma de base de données à utiliser pour effectuer les opérations de base de données demandées pour ce locataire.

Problème

Après avoir établi une connexion à une base de données (postgres) via TypeORM (par exemple en utilisant createConnection ), notre seule chance de définir le schéma d'une opération db est de recourir à la createQueryBuilder:

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

Cela signifie que nous sommes obligés d'utiliser le QueryBuilder car il ne semble pas possible de définir le schéma lorsque vous travaillez avec API EntityManager (ou API du référentiel ).

Cependant, nous voulons/devons utiliser ces API, car elles sont beaucoup plus simples à écrire, nécessitent moins de code et sont également moins sujettes aux erreurs, car elles ne reposent pas sur l'écriture de requêtes "manuellement" en utilisant une syntaxe basée sur des chaînes.

Question

Dans le cas de TypeORM, est-il possible de définir le schéma db d'une manière ou d'une autre lorsque vous travaillez avec EntityManager ou les référentiels?

Quelque chose comme ça?

// 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 })

Remarques:

  • Le schéma db doit être défini d'une manière limitée à la demande pour éviter de définir le schéma pour d'autres demandes, qui peuvent appartenir à d'autres clients. La définition du schéma pour l'ensemble de la connexion n'est pas une option.
  • Nous sommes conscients que l'on pourrait créer une toute nouvelle connexion et définir le schéma de cette connexion, mais nous voulons réutiliser la connexion existante. La création d'une nouvelle connexion pour définir le schéma n'est donc pas une option.
7
B12Toaster

Pour répondre à ma propre question:

Pour le moment, il n'y a aucun moyen d'instancier référentiels TypeORM avec différents schémas au moment de l'exécution sans créer de nouvelles connexions.

Ainsi, les deux seules options qui restent à un développeur pour la multi-location basée sur un schéma sont:

  1. Configuration de nouvelles connexions pour se connecter à différents schémas dans la même base de données au moment de l'exécution. Par exemple. voir NestJS Scoped Multitenancy pour plusieurs bases de données . Cependant, il faut absolument s'efforcer de réutiliser les connexions et être conscient de limites de connexion .
  2. Abandonner l'idée de travailler avec RepositoryApi et revenir à l'utilisation de createQueryBuilder (ou exécuter des requêtes SQL via query()).

Pour de plus amples recherches, voici quelques problèmes de TypeORM GitHub qui suivent l'idée de changer le schéma d'une connexion ou d'un référentiel existant au moment de l'exécution (similaire à ce qui est demandé dans l'OP):

P.S. Si TypeORM décide de soutenir l'idée discutée dans le PO, je vais essayer de mettre à jour cette réponse.

2
B12Toaster