多表联查

业务数据通常会进行分表,把数据按含义分开存放,然后通过关联关系(外键)进行联合查询

案例

21的案例中新增一个添加标签功能

前端

添加一点结构和逻辑

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<!-- 每列加了用于添加标签的按钮 -->
<el-button @click="(isShowTag = true,row = scope.row)">添加tag</el-button>

<!-- --------------我是分割线-------------- -->

<!-- 加了用于输入并添加标签的窗口 -->
<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="addTag" type="primary">确定</el-button>
</template>
</el-dialog>

<script>
// 加了用于添加标签的逻辑
const isShowTag = ref<boolean>(false)
const tags = ref<string[]>([])
const row = ref<{
id?: number,
name?: string,
desc?: string,
createTime?: Date
}>({})
const addTag = async () => {
const res = await addTags({
tags: tags.value,
userId: row.value.id
})
console.log(res)
isShowTag.value = false
tags.value = []
}
</script>
1
2
// 还加了联系后台添加标签的接口
export const addTags = (data: { tags: string[]; userId: number | undefined; }) => axios.post(`/user/add/tags`,data).then(res => res.data)

后端

一个用户可能拥有多个标签(反之,多个标签用于一个用户),它们是一对多(反之多对一)的关系:

在User文件夹中新建Tags实体:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import { Column, Entity, ManyToOne, PrimaryGeneratedColumn } from 'typeorm';
import { User } from './user.entity';

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

@Column()
name: string;

// 和User实体产生多对一的关联关系,@ManyToOne指多(自己)对一(关联实体)
// 参数:函数返回一个与之关联的实体
@ManyToOne(() => User)
user: User;
}

做好User实体和Tags实体的关联:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import { Column, Entity, OneToMany, PrimaryGeneratedColumn } from 'typeorm';
import { Tags } from './tags.entity';

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

@Column({ name: 'name' })
name: string;

@Column({ name: 'desc' })
desc: string;

// 和Tags实体产生一对多的关联关系,@OneToMany指一(自己)对多(关联实体)
// 参数1:函数返回一个与之关联的实体 参数2:函数返回一个反向关联时用的属性
@OneToMany(() => Tags, (tags) => tags.user)
tags: Tags[];
}

在Module中关联Tags表:

1
2
3
4
5
6
7
8
9
10
11
12
13
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 {}

在Controller中添加提交标签的接口:

1
2
3
4
@Post('/add/tags')
addTags(@Body() params: { tags: string[]; userId: number }) {
return this.userService.addTags(params);
}

在Service中实现有关标签的逻辑:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
import { Injectable } from '@nestjs/common';
import { CreateUserDto } from './dto/create-user.dto';
import { UpdateUserDto } from './dto/update-user.dto';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository, Like } from 'typeorm';
import { User } from './entities/user.entity';
import { Tags } from './entities/tags.entity';

@Injectable()
export class UserService {
// 依赖注入,装饰器接收实体参数
constructor(
@InjectRepository(User) private readonly user: Repository<User>,
@InjectRepository(Tags) private readonly tags: Repository<Tags>,
) {}

// 添加标签
async addTags(params: { tags: string[]; userId: number }) {
// Tags数组
const tagList: Tags[] = [];
// 遍历标签
for (let i = 0; i < params.tags.length; i++) {
const T = new Tags();
T.name = params.tags[i];
// 将标签逐个入表
await this.tags.save(T);
// 将标签逐个添至数组
tagList.push(T);
}

// 找到对应的user数据
const userInfo = await this.user.findOne({
where: {
id: params.userId,
},
});
// 给user赋上关联关系(实际上是给tags表的userId列赋值)
userInfo.tags = tagList;
// 当实体实例中有主键时,save方法执行修改操作
this.user.save(userInfo);
return true;
}

// 查询所有User
async findAll(query: { keyWord: string; page: number; pageSize: number }) {
console.log(query.keyWord);
const list = await this.user.find({
// 查询时添加关联关系,这样一来可以顺便查到tags表的关联内容了
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 {
list,
total,
};
}
// 省略...
}