QueryBuilder 是 TypeORM 中最强大、最灵活的查询工具,它允许开发者构建复杂的 SQL 查询,同时保持类型安全和可读性。
QueryBuilder 基础用法
创建 QueryBuilder
typescriptimport { DataSource } from 'typeorm'; const dataSource = new DataSource(/* 配置 */); // 方式1: 通过 Repository 创建 const userRepository = dataSource.getRepository(User); const queryBuilder = userRepository.createQueryBuilder('user'); // 方式2: 通过 DataSource 创建 const queryBuilder = dataSource.createQueryBuilder(User, 'user');
基本查询操作
typescript// 查询所有用户 const users = await dataSource .createQueryBuilder('user') .getMany(); // 查询单个用户 const user = await dataSource .createQueryBuilder('user') .where('user.id = :id', { id: 1 }) .getOne(); // 查询并计数 const count = await dataSource .createQueryBuilder('user') .getCount();
条件查询
Where 子句
typescript// 简单条件 const users = await dataSource .createQueryBuilder('user') .where('user.age > :age', { age: 18 }) .getMany(); // 多个条件 (AND) const users = await dataSource .createQueryBuilder('user') .where('user.age > :age', { age: 18 }) .andWhere('user.isActive = :isActive', { isActive: true }) .getMany(); // OR 条件 const users = await dataSource .createQueryBuilder('user') .where('user.age > :age', { age: 18 }) .orWhere('user.role = :role', { role: 'admin' }) .getMany(); // 复杂条件组合 const users = await dataSource .createQueryBuilder('user') .where( new Brackets(qb => { qb.where('user.age > :age', { age: 18 }) .orWhere('user.role = :role', { role: 'admin' }); }) ) .andWhere('user.isActive = :isActive', { isActive: true }) .getMany();
操作符
typescriptimport { Like, Between, In, MoreThan, LessThan } from 'typeorm'; // LIKE 查询 const users = await dataSource .createQueryBuilder('user') .where('user.name LIKE :name', { name: '%John%' }) .getMany(); // 或者使用 Like 操作符 const users = await dataSource .createQueryBuilder('user') .where('user.name = :name', { name: Like('%John%') }) .getMany(); // BETWEEN 查询 const users = await dataSource .createQueryBuilder('user') .where('user.age = :age', { age: Between(18, 30) }) .getMany(); // IN 查询 const users = await dataSource .createQueryBuilder('user') .where('user.id IN :ids', { ids: [1, 2, 3] }) .getMany(); // 或者使用 In 操作符 const users = await dataSource .createQueryBuilder('user') .where('user.id = :ids', { ids: In([1, 2, 3]) }) .getMany(); // 比较操作符 const users = await dataSource .createQueryBuilder('user') .where('user.age = :age', { age: MoreThan(18) }) .andWhere('user.score = :score', { score: LessThan(100) }) .getMany();
关联查询
Left Join 和 Inner Join
typescript// Left Join (包含没有关联数据的记录) const users = await dataSource .createQueryBuilder('user') .leftJoinAndSelect('user.posts', 'post') .where('user.id = :id', { id: 1 }) .getMany(); // Inner Join (只包含有关联数据的记录) const users = await dataSource .createQueryBuilder('user') .innerJoinAndSelect('user.posts', 'post') .where('user.id = :id', { id: 1 }) .getMany(); // 多层关联 const users = await dataSource .createQueryBuilder('user') .leftJoinAndSelect('user.posts', 'post') .leftJoinAndSelect('post.comments', 'comment') .leftJoinAndSelect('comment.author', 'commentAuthor') .getMany();
Join 条件
typescriptconst users = await dataSource .createQueryBuilder('user') .leftJoin('user.posts', 'post', 'post.status = :status', { status: 'published' }) .addSelect(['post.title', 'post.createdAt']) .getMany();
排序和分页
排序
typescript// 单字段排序 const users = await dataSource .createQueryBuilder('user') .orderBy('user.createdAt', 'DESC') .getMany(); // 多字段排序 const users = await dataSource .createQueryBuilder('user') .orderBy('user.createdAt', 'DESC') .addOrderBy('user.name', 'ASC') .getMany(); // 随机排序 (MySQL) const users = await dataSource .createQueryBuilder('user') .orderBy('RAND()') .getMany();
分页
typescript// 基本分页 const page = 1; const pageSize = 10; const users = await dataSource .createQueryBuilder('user') .skip((page - 1) * pageSize) .take(pageSize) .getMany(); // 获取总数和分页数据 const [users, total] = await dataSource .createQueryBuilder('user') .skip((page - 1) * pageSize) .take(pageSize) .getManyAndCount(); console.log(`Total: ${total}, Page: ${page}, PageSize: ${pageSize}`);
聚合查询
Group By 和 Having
typescript// 按角色分组统计用户数 const result = await dataSource .createQueryBuilder('user') .select('user.role', 'role') .addSelect('COUNT(*)', 'count') .groupBy('user.role') .getRawMany(); // 使用 Having 过滤分组 const result = await dataSource .createQueryBuilder('user') .select('user.role', 'role') .addSelect('COUNT(*)', 'count') .groupBy('user.role') .having('COUNT(*) > :minCount', { minCount: 5 }) .getRawMany();
聚合函数
typescript// 统计总数 const count = await dataSource .createQueryBuilder('user') .select('COUNT(*)', 'count') .getRawOne(); // 计算平均值 const avgAge = await dataSource .createQueryBuilder('user') .select('AVG(user.age)', 'avgAge') .getRawOne(); // 求和 const totalScore = await dataSource .createQueryBuilder('user') .select('SUM(user.score)', 'totalScore') .getRawOne(); // 最大值和最小值 const result = await dataSource .createQueryBuilder('user') .select('MAX(user.age)', 'maxAge') .addSelect('MIN(user.age)', 'minAge') .getRawOne();
子查询
使用 SubQueryFactory
typescriptimport { SubQueryFactory } from 'typeorm'; const users = await dataSource .createQueryBuilder('user') .where((qb: SelectQueryBuilder<User>) => { const subQuery = qb .subQuery() .select('post.userId') .from(Post, 'post') .where('post.title LIKE :title', { title: '%TypeORM%' }) .getQuery(); return 'user.id IN ' + subQuery; }) .setParameter('title', '%TypeORM%') .getMany();
使用 EXISTS
typescriptconst users = await dataSource .createQueryBuilder('user') .where((qb: SelectQueryBuilder<User>) => { const subQuery = qb .subQuery() .select('1') .from(Post, 'post') .where('post.userId = user.id') .getQuery(); return 'EXISTS ' + subQuery; }) .getMany();
更新和删除
更新操作
typescript// 简单更新 await dataSource .createQueryBuilder(User, 'user') .update() .set({ name: 'Updated Name' }) .where('id = :id', { id: 1 }) .execute(); // 条件更新 await dataSource .createQueryBuilder(User, 'user') .update() .set({ isActive: false }) .where('user.lastLoginAt < :date', { date: new Date('2024-01-01') }) .execute(); // 基于子查询的更新 await dataSource .createQueryBuilder(User, 'user') .update() .set({ score: () => 'score + 10' }) .where('user.id IN :ids', { ids: [1, 2, 3] }) .execute();
删除操作
typescript// 简单删除 await dataSource .createQueryBuilder(User, 'user') .delete() .where('id = :id', { id: 1 }) .execute(); // 条件删除 await dataSource .createQueryBuilder(User, 'user') .delete() .where('user.createdAt < :date', { date: new Date('2023-01-01') }) .andWhere('user.isActive = :isActive', { isActive: false }) .execute();
高级特性
原生 SQL
typescriptconst users = await dataSource .createQueryBuilder(User, 'user') .where('user.id = :id', { id: 1 }) .andWhere('JSON_CONTAINS(user.preferences, :preferences)', { preferences: JSON.stringify({ theme: 'dark' }) }) .getMany();
缓存
typescriptconst users = await dataSource .createQueryBuilder('user') .where('user.isActive = :isActive', { isActive: true }) .cache(60000) // 缓存 60 秒 .getMany();
事务
typescriptawait dataSource.transaction(async transactionalEntityManager => { const queryRunner = transactionalEntityManager.queryRunner; await queryRunner.manager .createQueryBuilder(User, 'user') .insert() .values({ name: 'John', email: 'john@example.com' }) .execute(); await queryRunner.manager .createQueryBuilder(Post, 'post') .insert() .values({ title: 'New Post', authorId: 1 }) .execute(); });
性能优化建议
- 避免 N+1 查询: 使用
leftJoinAndSelect一次性加载关联数据 - 只选择需要的字段: 使用
select()明确指定需要的列 - 合理使用索引: 为常用查询条件添加数据库索引
- 使用缓存: 对不常变化的数据启用查询缓存
- 限制返回结果: 使用
take()和skip()实现分页 - 监控查询性能: 使用
getQuery()和getSql()查看生成的 SQL
QueryBuilder 是 TypeORM 中最强大的查询工具,掌握它的使用可以让你构建出高效、灵活的数据库查询。