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中用法
- 首先代码中关联了两个实体类,该前置类为:
SheepEntity
、CowEntity
,在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
更简洁明了,并且通俗易通