NestJS最佳实践--#7 软删除及恢复实现回收站功能
文章发布在专栏NestJS最佳实践中
学习目标
- 软删除与恢复
- 批量删除与批量恢复
什么是软删除
软删除是一种广泛应用于业务应用程序的模式。它允许您将一些记录标记为已删除,而无需从数据库中真正删除。因此,可以在防止软删除的记录被选中的同时,旧记录仍然可以被引用。
通过软删除,我们可以实现类似于回收站的功能,比如将文章软删除后放进回收站,后面也可以从回收站中恢复。
TypeORM软删除及恢复用法
-
在Entity中使用
@DeleteDateColumn()
装饰器@DeleteDateColumn() public deletedAt: Date;
-
软删除: 使用
softRemove
替代remove
- 执行
softRemove
后deletedAt
由null
变为具体删除日期
- 执行
-
恢复: 使用
restore
方法恢复数据- 执行
restore
后deletedAt
由具体删除日期变为null
- 执行
-
查询: 当我们使用
find()
或类似方法查询时,TypeORM会自动取查询deletedAt
为NULL
的记录,当然我们也可以指定withDeleted
字段来控制是否查询软删除数据const category = await this.categoriesRepository.findOne(id, { relations: ['posts'], withDeleted: true }
如下图所示, deletedAt
一列为日期代表该条数据被软删除,为null
则为正常数据
批量删除与恢复DTO
因为各模块都会用到软删除及恢复功能,因此我们提取出DeleteDto
和 RestoreDto
到 src/common/dtos
目录下,作为全局公用DTO
/**
* 批量删除
*/
export class DeleteDto {
@IsUUID(undefined, { each: true, message: 'ID格式错误' })
@IsDefined({ each: true, message: 'ID必须指定' })
ids: string[] = [];
// 是否为软删除
@Transform(({ value }) => Boolean(value))
@IsBoolean()
@IsOptional()
soft?: boolean;
}
/**
* 批量恢复
*/
export class RestoreDto {
@IsUUID(undefined, { each: true, message: 'ID格式错误' })
@IsDefined({ each: true, message: 'ID必须指定' })
ids: string[] = [];
}
软删除及数据恢复
接下来我们要实现文章模块的软删除及数据恢复
首先给QueryPostDto
加上soft
字段用来判断是否查询软删除数据
@DtoValidation({ groups: ['query'] })
export class QueryPostDto extends PaginationDto {
@IsUUID(undefined, { message: '分类ID格式错误' })
@IsOptional()
category?: string;
@IsEnum(SelectSoftDeleteMode)
@IsOptional()
soft?: SelectSoftDeleteMode;
}
@IsEnum
: 校验soft值是否为指定枚举值
接下来修改一下PostService
- DeleteDto中soft为true代表软删除,要执行
softRemove
- DeleteDto中soft不设置或设为false,代表物理删除,要执行
remove
@Injectable()
export class PostService {
// ...
async remove({ ids, soft }: DeleteDto) {
const posts = await this.postsRepository.find({
where: { id: In(ids) },
withDeleted: false, // 过滤掉已删除的
});
if (soft) return this.postsRepository.softRemove(posts);
return this.postsRepository.remove(posts);
}
async restore({ ids }: RestoreDto) {
const posts = await this.postsRepository.find({
where: { id: In(ids) },
withDeleted: true,
});
// 过滤掉不在回收站中的数据
const deletedIds = posts.filter((post) => !isNil(post.deletedAt)).map((post) => post.id);
this.postsRepository.restore(deletedIds);
}
// ...
}
最后修改下PostController
@Controller('post')
export class PostController {
// ...
@Post('delete')
remove(@Body() data: DeleteDto) {
return this.postService.remove(data);
}
@Patch('restore')
restore(@Body() data: RestoreDto) {
return this.postService.restore(data);
}
// ...
}
这样我们就实现了文章的批量删除,软删除与批量恢复功能啦.至于分类和评论模块的软删除与恢复,代码与文章模块类似, 只不过要注意下树形结构的级联操作,这里就不再赘述。
转载自:https://juejin.cn/post/7215422960815767613