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

TypeORM中查询虚拟列slugWithUuid报错,求可行查询方案

问题描述

我定义了如下Course实体,通过@AfterLoad钩子生成虚拟列slugWithUuid,该列由slug与additionalInfoJSON中的uuid拼接而成:

@Entity()
export class Course extends DefaultCredential {
  @Column({ type: 'varchar', length: 75 })
  title: string;

  @Column({ type: 'varchar', length: 50 })
  slug: string;

  @Column({ type: 'json', nullable: true })
  additionalInfoJSON: any;

  slugWithUuid: string;
  @AfterLoad()
  setCustomProperty() {
    this.slugWithUuid =
      this.slug + '-' + JSON.parse(this.additionalInfoJSON)?.uuid;
  }

  @BeforeInsert()
  insertShortUUID() {
    const shortUUID = generateUUID(6);
    const additionalInfo = {
      ...this.additionalInfoJSON,
      uuid: shortUUID,
    };
    this.additionalInfoJSON = JSON.stringify(additionalInfo);
  }
}

当我使用如下代码查询该虚拟列时:

async findBySlug(slug: string) {
    const entity = await this.repos.findOne({
      where: { slugWithUuid: slug }
    });

    if (!entity) {
      throw new NotFoundException('Entity not found with this slug');
    }
    return entity;
  }

出现报错:

[Nest] 637270 - 10/03/2024, 9:37:42 AM ERROR [ExceptionsHandler]
Property "slugWithUuid" was not found in "Course". Make sure your
query is correct. EntityPropertyNotFoundError: Property "slugWithUuid"
was not found in "Course". Make sure your query is correct.

请问是否有其他声明虚拟列的方式,使其能够支持查询过滤?

解决方案

方法1:数据库原生虚拟列(推荐)

直接在数据库层面定义虚拟列,让ORM能识别并支持查询。以MySQL为例,修改实体字段的@Column配置:

@Column({ 
  type: 'varchar', 
  length: 100,
  // MySQL语法:拼接slug与JSON中的uuid
  asExpression: "CONCAT(slug, '-', JSON_UNQUOTE(JSON_EXTRACT(additionalInfoJSON, '$.uuid')))",
  generated: 'virtual' // 可选'persisted'将值持久化到数据库,提升查询性能但占用存储空间
})
slugWithUuid: string;

注意:不同数据库的JSON处理语法不同,比如PostgreSQL用json_extract_path_text,SQL Server用JSON_VALUE,需对应调整。

方法2:查询时手动拼接匹配条件

不依赖虚拟列,直接在查询条件中拆分并匹配原字段:

async findBySlug(slug: string) {
  // 拆分传入的slug,分离原slug和uuid部分
  const [originalSlug, uuid] = slug.split('-');
  
  const entity = await this.repos.findOne({
    where: {
      slug: originalSlug,
      additionalInfoJSON: Raw(alias => 
        `${alias}->>'$.uuid' = :uuid`, 
        { uuid }
      )
    }
  });

  if (!entity) {
    throw new NotFoundException('Entity not found with this slug');
  }
  return entity;
}

这里用Raw函数生成原生SQL条件,匹配JSON字段中的uuid值。

方法3:使用数据库视图

创建包含slugWithUuid的视图,再定义对应的视图实体:

  1. 创建视图SQL(MySQL示例):
CREATE VIEW course_view AS
SELECT 
  *,
  CONCAT(slug, '-', JSON_UNQUOTE(JSON_EXTRACT(additionalInfoJSON, '$.uuid'))) AS slugWithUuid
FROM course;
  1. 定义视图实体:
@Entity('course_view')
export class CourseView extends DefaultCredential {
  @Column({ type: 'varchar', length: 75 })
  title: string;

  @Column({ type: 'varchar', length: 50 })
  slug: string;

  @Column({ type: 'json', nullable: true })
  additionalInfoJSON: any;

  @Column({ type: 'varchar', length: 100 })
  slugWithUuid: string;
}

之后可通过CourseView实体直接查询slugWithUuid字段。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 18:22:46