gpt4 book ai didi

typeorm - NestJS : database connection (TypeORM) by request (subdomain)

转载 作者:行者123 更新时间:2023-12-04 12:39:12 28 4
gpt4 key购买 nike

我正在尝试通过 Nest/TypeORM 构建 SAAS 产品,我需要按子域配置/更改数据库连接。

customer1.domain.com => connect to customer1 database
customer2.domain.com => connect to customer2 database
x.domain.com => connect to x database

我怎样才能做到这一点 ?使用拦截器或请求上下文(或 Zone.js)?

我不知道如何开始。有人已经这样做了吗?

WIP:我目前在做什么:
  • 将所有连接设置添加到 ormconfig 文件
  • 在所有路由上创建中间件以将子域注入(inject) res.locals (实例名称)并创建/警告 typeorm 连接
    import { Injectable, NestMiddleware, MiddlewareFunction } from '@nestjs/common';
    import { getConnection, createConnection } from "typeorm";

    @Injectable()
    export class DatabaseMiddleware implements NestMiddleware {
    resolve(): MiddlewareFunction {
    return async (req, res, next) => {
    const instance = req.headers.host.split('.')[0]
    res.locals.instance = instance

    try {
    getConnection(instance)
    } catch (error) {
    await createConnection(instance)
    }

    next();
    };
    }
    }
  • 在 Controller 中:从 @Response 获取实例名称并将其传递给我的服务
    @Controller('/catalog/categories')
    export class CategoryController {
    constructor(private categoryService: CategoryService) {}

    @Get()
    async getList(@Query() query: SearchCategoryDto, @Response() response): Promise<Category[]> {
    return response.send(
    await this.categoryService.findAll(response.locals.instance, query)
    )
    }
  • 在服务中:获取给定实例的 TypeORM 管理器并通过存储库查询数据库
    @Injectable()
    export class CategoryService {
    // constructor(
    // @InjectRepository(Category) private readonly categoryRepository: Repository<Category>
    // ) {}

    async getRepository(instance: string): Promise<Repository<Category>> {
    return (await getManager(instance)).getRepository(Category)
    }

    async findAll(instance: string, dto: SearchCategoryDto): Promise<Category[]> {
    let queryBuilder = (await this.getRepository(instance)).createQueryBuilder('category')

    if (dto.name) {
    queryBuilder.andWhere("category.name like :name", { name: `%${dto.name}%` })
    }

    return await queryBuilder.getMany();
    }

  • 它似乎有效,但我几乎不确定所有事情:
  • 连接池(我可以在我的 ConnectionManager 中创建多少连接?)
  • 将子域传递到 response.locals... 不好的做法?
  • 可读性/理解/添加大量附加代码...
  • 副作用:我害怕在几个子域之间共享连接
  • 副作用:性能

  • 处理 response.send() + Promise + await(s) + pass subdomain到处都是不愉快的......

    有没有办法让子域直接进入我的服务?

    有没有办法让正确的子域连接/存储库直接进入我的服务并将其注入(inject)我的 Controller ?

    最佳答案

    我想出了另一个解决方案。

    我创建了一个中间件来获取特定租户的连接:

    import { createConnection, getConnection } from 'typeorm';
    import { Tenancy } from '@src/tenancy/entity/tenancy.entity';

    export function tenancyConnection(...modules: Array<{ new(...args: any[]):
    any; }>) {

    return async (req, res, next) => {

    const tenant = req.headers.host.split(process.env.DOMAIN)[0].slice(0, -1);

    // main database connection
    let con = ...

    // get db config that is stored in the main db
    const tenancyRepository = await con.getRepository(Tenancy);
    const db_config = await tenancyRepository.findOne({ subdomain: tenant });

    let connection;
    try {
    connection = await getConnection(db_config.name);
    } catch (e) {
    connection = await createConnection(db_config.config);
    }

    // stores connection to selected modules
    for (let module of modules) {
    Reflect.defineMetadata('__tenancyConnection__', connection, module);
    }

    next();
    };
    }

    我将它添加到 main.ts:
    const app = await NestFactory.create(AppModule);
    app.use(tenancyConnection(AppModule));

    要访问连接,您可以通过以下方式扩展任何服务:
    export class TenancyConnection {

    getConnection(): Connection {
    return Reflect.getMetadata('__tenancyConnection__', AppModule);
    }
    }

    它仍然是一个草稿,但使用此解决方案,您可以在运行时为每个租户添加、删除和编辑连接。
    我希望这可以进一步帮助您。

    关于typeorm - NestJS : database connection (TypeORM) by request (subdomain),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51385738/

    28 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com