NestJS之20- 连表查询

1,045 阅读2分钟

1. 前端代码

curd.vue

<template>
	<div class="wraps">
		<div>
			<el-input v-model="search.keyWord" style="width: 300px"></el-input>
			<el-button @click="init" style="margin-left: 10px">搜索</el-button>
			<el-button @click="openDialog" type="primary" style="margin-left: 10px">添加</el-button>
		</div>
		<el-table border :data="tableData" style="width: 100%; margin-top: 30px">
			<el-table-column prop="name" label="名字" />
			<el-table-column prop="desc" label="描述" />

			<el-table-column prop="id" label="id" />
			<el-table-column>
				<template #default="scope">
					<el-button @click="edit(scope.row)">编辑</el-button>
					<el-button @click="deleteRow(scope.row)">删除</el-button>
					<el-button @click=";(isShowTag = true), (row = scope.row)">添加tag</el-button>
				</template>
			</el-table-column>
		</el-table>
		<el-pagination
			@current-change="change"
			style="float: right; margin-top: 10px"
			background
			layout="prev, pager, next"
			:total="total"
		/>
	</div>

	<el-dialog v-model="dialogVisible" title="弹框" width="50%">
		<el-form :model="form">
			<el-form-item prop="name" label="名称">
				<el-input v-model="form.name" placeholder="名称" />
			</el-form-item>
			<el-form-item prop="desc" label="描述">
				<el-input v-model="form.desc" placeholder="描述"> </el-input>
			</el-form-item>
		</el-form>
		<template #footer>
			<span class="dialog-footer">
				<el-button @click="close">关闭</el-button>
				<el-button type="primary" @click="save"> 保存 </el-button>
			</span>
		</template>
	</el-dialog>
	<el-dialog v-model="isShowTag" title="添加tag">
		<el-select style="width: 100%" v-model="tags" multiple>
			<el-option value="tag1">tag1</el-option>
			<el-option value="tag2">tag2</el-option>
			<el-option value="tag3">tag3</el-option>
		</el-select>
		<template #footer>
			<el-button @click="addTa" type="primary">确定</el-button>
		</template>
	</el-dialog>
</template>

<script setup>
import { ref, reactive } from 'vue'
import { addUser, updateUser, delUser, getList, addTags } from '../apis'
const isShowTag = ref(false)
const tags = ref([])
const total = ref(0)
const row = ref({})
const addTa = async () => {
	const res = await addTags({
		tags: tags.value,
		userId: row.value.id
	})
	isShowTag.value = false
	tags.value = []
}
//搜索框
const search = reactive({
	keyWord: '',
	page: 1,
	pageSize: 10
})
//表单
const form = reactive({
	name: '',
	desc: '',
	id: 0
})
//清空数据
const resetForm = reactive({ ...form })
//表格数据
const tableData = ref([])
//弹框开关
const dialogVisible = ref(false)
const openDialog = () => {
	dialogVisible.value = true
	Object.assign(form, resetForm)
}
//初始化表格数据
const init = async () => {
	const list = await getList(search)
	tableData.value = list?.data ?? []
	total.value = list?.total ?? 0
}
init()
const change = page => {
	search.page = page
	init()
}
//保存 和修改 表格数据
const save = async () => {
	if (form.id) {
		await updateUser(form)
	} else {
		await addUser(form)
	}

	close()
	init()
}
//删除表格数据
const deleteRow = async row => {
	await delUser({ id: row.id })
	init()
}
//获取 详情
const edit = row => {
	dialogVisible.value = true
	Object.assign(form, row)
}
//关闭弹框
const close = () => {
	dialogVisible.value = false
}
</script>

<style>
* {
	padding: 0;
	margin: 0;
}

html,
body {
	width: 100%;
	background: #ccc;
}

.wraps {
	display: flex;
	flex-direction: column;
	height: 100vh;
	padding: 30px;
}
</style>

api

import axios from 'axios'

axios.defaults.baseURL = 'http://localhost:3000'

//添加tag
export const addTags = (data) => axios.post(`/user/add/tags`,data).then(res => res.data)

2. 后端

整体流程:

image.png

  1. 新建一个tags.entity.ts
import {
  Column,
  Entity,
  PrimaryGeneratedColumn,
  JoinColumn,
  ManyToOne,
} from 'typeorm';
import { User } from './user.entity';
@Entity()
export class Tags {
  @PrimaryGeneratedColumn()
  id: number;

  @Column()
  tags: string;

  @ManyToOne(() => User, (user) => user.tags)
  @JoinColumn()
  user: User;
}

  1. 修改user.entity.ts
import {
  PrimaryGeneratedColumn,
  Column,
  Generated,
  CreateDateColumn,
  Entity,
  OneToMany,
} from 'typeorm';

import { Tags } from './tags.entity';

@Entity()
export class User {
  @PrimaryGeneratedColumn()
  id: number;

  @Column({ type: 'varchar', length: 255 })
  name: string;

  @Column({ type: 'text' })
  desc: string;

  @Generated('uuid')
  uuid: string;

  @CreateDateColumn({ type: 'timestamp' })
  createTime: Date;

  @OneToMany(() => Tags, (tags) => tags.user)
  tags: Tags[];
}

  1. 在user.module.ts的imports中加入Tags的实体
import { Module } from '@nestjs/common';
import { UserService } from './user.service';
import { UserController } from './user.controller';
import { TypeOrmModule } from '@nestjs/typeorm';
import { User } from './entities/user.entity';
import { Tags } from './entities/tags.entity';

@Module({
  imports: [TypeOrmModule.forFeature([User, Tags])],
  controllers: [UserController],
  providers: [UserService],
})
export class UserModule {}

  1. user.controller.ts 中写添加标签的代码
  @Post('/add/tags')
  addTags(@Body() params: { tags: string[]; userId: number }) {
    return this.userService.addTags(params);
  }
  1. user.service.ts 写存入tag数据库的操作,表格进行连表查询使用relation进行关联
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Like, Repository } from 'typeorm';
import { CreateUserDto } from './dto/create-user.dto';
import { UpdateUserDto } from './dto/update-user.dto';
import { Tags } from './entities/tags.entity';
import { User } from './entities/user.entity';

@Injectable()
export class UserService {
  constructor(
    @InjectRepository(User) private readonly user: Repository<User>,
    @InjectRepository(Tags) private readonly tag: Repository<Tags>,
  ) {}

  //通过前端传入的userId 查到当前id 的用户信息,然后拿到前端传入的tags [tag1,tag2,tag3]
  // 进行遍历 给tag实例进行赋值 然后调用保存方法添加tag 添加完之后 通过 tagList 保存该tag类
  // 最后把tagList 赋给 user类的tags属性 然后重新调用save 进行更新
  async addTags(params: { tags: string[]; userId: number }) {
    const userInfo = await this.user.findOne({ where: { id: params.userId } });
    const tagList: Tags[] = [];
    for (let i = 0; i < params.tags.length; i++) {
      const T = new Tags();
      T.tags = params.tags[i];
      await this.tag.save(T);
      tagList.push(T);
    }
    userInfo.tags = tagList;
    console.log(userInfo, 1);
    return this.user.save(userInfo);
  }

  async findAll(query: { keyWord: string; page: number; pageSize: number }) {
    const data = await this.user.find({
      //查询的时候如果需要联合查询需要增加 relations
      relations: ['tags'],
      where: {
        name: Like(`%${query.keyWord}%`),
      },
      order: {
        id: 'DESC',
      },
      skip: (query.page - 1) * query.pageSize,
      take: query.pageSize,
    });
    const total = await this.user.count({
      where: {
        name: Like(`% ${query.keyWord} %`),
      },
    });
    return {
      data,
      total,
    };
  }

}

tag 表

image.png

user表

image.png

结果

image.png