对比TypeORM官网和在Nestjs用法,写个不一样的学习教程

41 阅读2分钟

TypeORM的官网用法和在NestJS中用法对比

连接数据库表并进行查询

原始用法

import { Injectable } from '@nestjs/common';
import { DataSource } from 'typeorm';
import { User } from './user.entity';

@Injectable()
export class UserService {
  constructor(
    private dataSource: DataSource,
  ) {}

  async findUserById(id: number): Promise<User> {
    // 手动获取 Repository 并构建查询
    const firstUser = await this.dataSource
      .getRepository(User)
      .createQueryBuilder("user")
      .where("user.id = :id", { id: 1 })
      .getOne();
    return firstUser;
  }
}

在Nest中用法

import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { User } from './user.entity';

@Injectable()
export class UserService {
  constructor(
    @InjectRepository(UserEntity)
    private userRepository: Repository<User>,
  ) {}

  async findUserById(id: number): Promise<User> {
    // 使用 @InjectRepository 注入的 Repository 对象进行查询
    return await this.userRepository.findOneBy({ id });
  }
}

对比

  • dataSource.getRepository(User).createQueryBuilder("user") 的对比

    • @InjectRepository:

      • 直接注入: 将一个已经配置好的 Repository 对象直接注入到服务中。
      • 类型安全: TypeScript 可以提供类型检查,确保注入的类型正确。
      • 简化代码: 省去了手动获取 Repository 的步骤。
    • dataSource.getRepository(User).createQueryBuilder("user"):

      • 手动获取: 需要通过数据源(dataSource)手动获取 Repository 对象,然后创建一个 QueryBuilder 对象。
      • 灵活性高: 可以自定义查询条件和排序方式。
      • 代码冗余: 如果在多个地方都需要进行类似的查询,会造成代码重复。

总结

  • 本质上,都是为了实现对数据库的访问
  • 区别上,一个是通过依赖注入直接获取,另一个是手动获取并构建查询
  • 选择上:
    • 建议优先使用 @InjectRepository,因为它更简洁、类型安全,并且符合NestJS的依赖注入机制
    • 使用手动获取的场景,在一些复杂的查询场景下,可能需要手动构建QueryBuilder,已获取更灵活的控制

多表关联时怎么联动查询

官网写法

const result = await dataSource
    .createQueryBuilder('user')
    .leftJoinAndSelect('user.linkedSheep', 'linkedSheep')
    .leftJoinAndSelect('user.linkedCow', 'linkedCow')
    .where('user.linkedSheep = :sheepId', { sheepId })
    .andWhere('user.linkedCow = :cowId', { cowId });

为了照顾入门者,代码逐行解析

const result = await dataSource.createQueryBuilder('user')
创建了一个新的 QueryBuilder 实例,并将其别名为 `user`。这将作为后续查询的基底。

.leftJoinAndSelect('user.linkedSheep', 'linkedSheep')
 执行了一个左外连接。这意味着即使 `user` 没有关联的 `linkedSheep`,也会被包含在结果中。
 将关联的 `linkedSheep` 表别名为 `linkedSheep`,以便后续引用。

.leftJoinAndSelect('user.linkedCow', 'linkedCow')

同样执行了一个左外连接,将 `linkedCow` 表别名为 `linkedCow`。

.where('user.linkedSheep = :sheepId', { sheepId })
添加了一个 `WHERE` 条件,筛选出 `linkedSheep`ID 等于 `sheepId` 的用户。

.andWhere('user.linkedCow = :cowId', { cowId })
添加了一个 `AND` 条件,进一步筛选出 `linkedCow`ID 等于 `cowId` 的用户。

在Nest中用法

  • 首先代码中关联了两个实体类,该前置类为:SheepEntityCowEntity,在UserEntity中关联如下
// user.entity.ts 
import { Entity, PrimaryGeneratedColumn, Column, OneToOne, JoinColumn } from 'typeorm'; 
import { SheepEntity } from './sheep.entity'; 
import { CowEntity } from './cow.entity'; 

@Entity() 
export class User {
  @PrimaryGeneratedColumn()
  id: number; 
  
  @Column() 
  firstName: string; 
  
  @Column() 
  lastName: string; 
  
  @OneToOne(() => Sheep, sheep => sheep.user) 
  @JoinColumn() 
  linkedSheep: SheepEntity; 
  
  @OneToOne(() => Cow, cow => cow.user) 
  @JoinColumn() 
  linkedCow: CowEntity; 
}
  • 修改user.service.ts
// user.service.ts
import { Injectable } from '@nestjs/common'; 
import { InjectRepository } from '@nestjs/typeorm'; 
import { Repository } from 'typeorm'; 
import { User } from './user.entity'; 

@Injectable() 
export class UserService { 
   constructor( 
     @InjectRepository(User) 
     private usersRepository: Repository<User>, 
   ) {} 
   
   async findUserByLinkedSheepAndCow(sheepId: number, cowId: number): Promise<User | undefined> { 
     return await this.usersRepository.findOne({ 
       relations: ['linkedSheep', 'linkedCow'], // 确保加载关联实体 
       where: { 
         linkedSheep: { id: sheepId }, 
         linkedCow: { id: cowId }, 
       }, 
     }); 
  } 
}

总结

对于OneToOne这种形式,无疑使用@InjectRepository更简洁明了,并且通俗易通