开发中,很多实体对象(如用户、订单、商品等)都需要实现基本的创建(Create)、读取(Read)、更新(Update)、删除(Delete)功能,也就是 CURD 操作。以用户管理系统为例,如果没有 CURD 基类,每个具体的实体类(如管理员用户类、普通用户类等)都要自己编写创建用户、查询用户、更新用户信息、删除用户等方法。这样会导致大量的重复代码。创建 CURD 基类后,这些通用的 CURD 方法可以集中定义在基类中,各个实体子类只需继承基类,就可以直接使用这些方法,大大减少了代码的冗余。
目录 1、创建基础实体类 2、创建服务器基类 3、创建控制器基类 4、使用基类示例
1、创建基础实体类
实体基类可以包括一些每个表都有的字段,如主键id,创建人、创建日期、备注等字段。
//base/base.entity.ts
import { Column, Entity, Int32, PrimaryGeneratedColumn } from "typeorm";
@Entity()
export class BaseEntity{
@PrimaryGeneratedColumn({type: 'int'})
id: number;
@Column()
createdAt: Date;
@Column()
updatedAt: Date;
}
2、创建服务器基类
注意:构造函数未使用 @InjectRepository注解,我们会在继承种使用该注解,并使用super函数调用基类种的构造函数。
//base/base.service.ts
import { Injectable } from '@nestjs/common';
import { DeleteResult, Repository, UpdateResult } from 'typeorm';
@Injectable()
export abstract class BaseService<T> {
constructor(
protected repository: Repository<T>,
) {
}
async findAll(): Promise<T[]> {
return this.repository.find();
}
async findOne(id: number): Promise<T> {
const record = await this.findOne(id);
if (!record) throw new Error('Record not found');
return record;
}
async create(data: Partial<T>): Promise<T[]> {
return this.repository.create(data as any);
}
async update(id: number, data: Partial<T>): Promise<UpdateResult> {
return this.repository.update(id, data as any);
}
async delete(id: number): Promise<DeleteResult> {
return this.repository.delete(id);
}
}
3、创建控制器基类
//base/base.controller.ts
import { Controller, Get, Post, Body, Param, Put, Delete } from '@nestjs/common';
@Controller()
export abstract class BaseController<T> {
constructor(protected readonly service: any) {}
@Get()
findAll() {
return this.service.findAll();
}
@Get(':id')
findOne(@Param('id') id: string) {
return this.service.findOne(+id);
}
@Post()
create(@Body() data: any) {
return this.service.create(data);
}
@Put(':id')
update(@Param('id') id: string, @Body() data: any) {
return this.service.update(+id, data);
}
@Delete(':id')
delete(@Param('id') id: string) {
return this.service.delete(+id);
}
}
4、使用基类示例
4.1、创建模块
使用下面指令创建一个test模块。
nest g res test --no-spec
4.2、修改实体基类
让实体基类继承自基类,通用字段就可以省略了。
// test.entity.ts
import { BaseEntity } from 'src/base/base.entity';
import { Entity, Column } from 'typeorm';
@Entity("test")
export class Test extends BaseEntity{
@Column()
name: string;
@Column({ unique: true })
email: string;
}
4.3、修改服务类
修改服务类,继承自BaseService,这样基础的CURD功能就具备了。注意构造函数中必须要有super调用父类。此处我们新增加了一个方法findTest,也可以用同名方式覆盖基类中的方法。
// test.service.ts
import { Injectable } from '@nestjs/common';
import { Test } from './entities/test.entity';
import { BaseService } from 'src/base/base.service';
import { UpdateTestDto } from './dto/update-test.dto';
import { InjectRepository } from '@nestjs/typeorm';
import { EntitySchema, Repository } from 'typeorm';
@Injectable()
export class TestService extends BaseService<Test> {
constructor(
@InjectRepository(Test)
protected repository: Repository<Test>,
) {
super(repository);
}
async findTest(): Promise<UpdateTestDto[]> {
const bb= await this.repository.find();
return bb;
}
}
4.4、修改控制器
让控制器继承自基类,并调用super方法。新增加一个findTest接口用于测试。
// test.controller.ts
import { Controller, Get } from '@nestjs/common';
import { TestService } from './test.service';
import { BaseController } from 'src/base/base.controller';
import { UpdateTestDto } from './dto/update-test.dto';
@Controller('test')
export class TestController extends BaseController<UpdateTestDto> {
constructor(private readonly userService: TestService) {
super(userService);
}
@Get("all")
async findTest(): Promise<UpdateTestDto[]> {
return await this.userService.findTest() as UpdateTestDto[];
}
}
4.5、模块代码如下
注意必须导入TypeOrmModule.forFeature([Test])。
import { Module } from '@nestjs/common';
import { TestService } from './test.service';
import { Test } from './entities/test.entity';
import { TypeOrmModule } from '@nestjs/typeorm';
import { TestController } from './test.controller';
@Module({
imports: [
TypeOrmModule.forFeature([Test])
],
controllers: [TestController],
providers: [TestService],
})
export class TestModule {}
4.6、测试
在浏览器中输入http://localhost:8000/test,该接口会调用基类中的get方法。
在浏览器中输入http://localhost:8000/test/all