NestJS TypeORM如何通过单API查询结构相同表名不同的多表
TypeORM 对接同结构多存量表实现方案
核心适用场景:多表字段100%一致、仅表名不同、无数据库结构修改权限的存量库对接场景,全程不需要为每张表单独编写实体类。
1. 抽离公共字段基础实体
先把所有超市表共有的字段按数据库实际结构定义成抽象基类,不要加@Entity装饰器,仅做字段复用:
import { Column, PrimaryColumn } from 'typeorm'; // 字段定义必须和存量表完全对齐,字段名、类型、精度都不能有偏差 export abstract class BaseSupermarket { @PrimaryColumn({ name: 'id' }) id: number; @Column({ name: 'shop_name', length: 64 }) shopName: string; @Column({ name: 'region_code', length: 16 }) regionCode: string; @Column({ name: 'daily_turnover', type: 'decimal', precision: 12, scale: 2 }) dailyTurnover: number; // 其余公共字段按实际表结构补充即可 }
2. 动态生成对应表的仓储
不要用@InjectRepository固定注入单表仓储,直接注入数据源实例,在运行时根据传入的表名动态生成实体、获取对应仓储:
import { Injectable } from '@nestjs/common'; import { InjectDataSource } from '@nestjs/typeorm'; import { DataSource, Entity } from 'typeorm'; import { BaseSupermarket } from './entities/base-supermarket.entity'; @Injectable() export class SupermarketService { // 提前维护合法表名白名单,避免SQL注入 private readonly validTableNames = new Set([ 'supermarket_ny_1', 'supermarket_par_1', // 其余所有合法超市表名补充在这里 ]); constructor(@InjectDataSource() private readonly dataSource: DataSource) {} private getTableRepository(tableName: string) { // 表名校验,非法表名直接抛错 if (!this.validTableNames.has(tableName)) { throw new Error(`非法表名: ${tableName}`); } // 动态生成绑定了目标表名的实体类 const DynamicEntity = Entity(tableName)(class extends BaseSupermarket {}); return this.dataSource.getRepository(DynamicEntity); } }
3. 业务层正常调用
拿到动态仓储后,用法和普通静态注入的仓储完全一致,支持所有TypeORM查询方法:
async getShopList(tableName: string, page: number, pageSize: number) { const repo = this.getTableRepository(tableName); // 普通条件查询 // return repo.find({ where: { regionCode: 'NY' }, skip: (page-1)*pageSize, take: pageSize }); // 复杂查询用queryBuilder也完全兼容 return repo.createQueryBuilder('shop') .where('shop.daily_turnover > :threshold', { threshold: 1000 }) .orderBy('shop.id', 'DESC') .skip((page - 1) * pageSize) .take(pageSize) .getMany(); }
必看避坑项
- 对接存量库必须把TypeORM配置中的
synchronize字段设为false,禁止开启自动表结构同步,避免动态实体误改客户原有表结构 - 绝对不要直接把前端传入的表名参数直接传入
getTableRepository方法,必须走白名单校验,防止SQL注入 - 如果表之间有公共的关联关系,直接在
BaseSupermarket基类中写关联装饰器即可,动态生成的实体可以正常继承关联关系 - 不需要提前把所有动态实体注册到NestJS模块的
entities配置数组中,运行时生成的实体TypeORM会自动识别处理
内容的提问来源于stack exchange,提问作者Rok
相关产品推荐
相关产品推荐

