You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何基于内容优化TypeORM权限定义?NestJS+SQL Server场景

优化用户内容过滤的实现方案

1. 用TypeORM查询构建器关联权限表(推荐)

直接通过JOIN关联权限表,把两次数据库请求合并成一次,避免额外的权限ID查询步骤。以查询用户可见Asset为例:

public async findAllAssetsByUser(queryParams: QueryParamsDto, userId?: string): Promise<Asset[]> {
  const queryBuilder = this.assetsRepo.createQueryBuilder('asset');

  // 关联BuildingUserPermission表,过滤用户有权限的建筑
  queryBuilder
    .innerJoin('building_user_permission', 'bup', 'asset.buildingId = bup.buildingId')
    .where('bup.userId = :userId', { userId })
    // 追加业务查询条件
    .andWhere('asset.status = :status', { status: queryParams.status })
    // 分页与排序
    .skip(queryParams.skip)
    .take(queryParams.take)
    .orderBy('asset.createdAt', 'DESC');

  return queryBuilder.getMany();
}

如果需要同时校验Client层级的权限(比如用户需先拥有Client权限才能访问下属建筑),可以多层JOIN:

queryBuilder
  .innerJoin('building', 'b', 'asset.buildingId = b.id')
  .innerJoin('client_user_permission', 'cup', 'b.clientId = cup.clientId')
  .where('cup.userId = :userId', { userId });

2. 利用TypeORM实体关联映射

如果你的实体已经定义了多对多关系(比如User和Building通过BuildingUserPermission关联),可以直接通过实体关系过滤,代码更简洁:

首先确保User实体的关系定义:

@Entity()
export class User {
  @PrimaryGeneratedColumn()
  id: string;

  @ManyToMany(() => Building)
  @JoinTable({
    name: 'building_user_permission',
    joinColumn: { name: 'userId', referencedColumnName: 'id' },
    inverseJoinColumn: { name: 'buildingId', referencedColumnName: 'id' },
  })
  allowedBuildings: Building[];
}

然后查询时直接通过关联关系过滤:

public async findAllAssetsByUser(queryParams: QueryParamsDto, userId?: string): Promise<Asset[]> {
  return this.assetsRepo.find({
    where: {
      building: {
        users: { id: userId }
      },
      status: queryParams.status
    },
    relations: ['building', 'building.users'],
    skip: queryParams.skip,
    take: queryParams.take,
    order: { createdAt: 'DESC' }
  });
}

底层会自动生成JOIN语句,同样是一次查询完成权限过滤。

3. 自定义数据库视图(适合复杂权限场景)

如果权限逻辑涉及多层级关联(比如Country→Client→Building→Asset),可以把权限过滤逻辑封装成数据库视图,再映射为TypeORM实体直接查询:

创建视图示例:

CREATE VIEW v_user_allowed_assets AS
SELECT a.*
FROM Asset a
JOIN Building b ON a.buildingId = b.id
JOIN Client c ON b.clientId = c.id
JOIN BuildingUserPermission bup ON b.id = bup.buildingId
WHERE bup.userId = @userId;

映射视图为实体:

@ViewEntity({ name: 'v_user_allowed_assets' })
export class UserAllowedAsset {
  @PrimaryColumn()
  id: string;

  @Column()
  name: string;
  // 其他Asset字段...
}

查询时直接操作视图实体:

public async findAllAssetsByUser(queryParams: QueryParamsDto, userId?: string): Promise<UserAllowedAsset[]> {
  return this.userAllowedAssetRepo.find({
    where: { userId },
    skip: queryParams.skip,
    take: queryParams.take
  });
}

这种方式适合权限规则固定且复杂的场景,能大幅简化应用层代码。

4. 使用TypeORM子查询替代两次查询

如果不想用JOIN,也可以把权限ID查询改成子查询,合并成一次数据库请求:

public async findAllAssetsByUser(queryParams: QueryParamsDto, userId?: string): Promise<Asset[]> {
  const subQuery = this.buildingUserPermissionRepo
    .createQueryBuilder('bup')
    .select('bup.buildingId')
    .where('bup.userId = :userId', { userId });

  return this.assetsRepo.find({
    where: {
      buildingId: In(subQuery.getQuery()),
      status: queryParams.status
    },
    parameters: { userId },
    skip: queryParams.skip,
    take: queryParams.take
  });
}

这种方式逻辑和你原来的IN查询类似,但避免了两次数据库请求。


内容的提问来源于stack exchange,提问作者Jorge

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 01:50:27