在我们开始的过程中,肯定不会把数据存在一个表里面,我们会进行分表,把数据分开存,然后通过关联关系,联合查询。
typeOrm 文档 一对一 | TypeORM 中文文档
前端代码还是复用上一章的 增加了一个添加Tag
<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 lang='ts'>
import { ref, reactive } from 'vue'
import type { FormInstance } from 'element-plus'
import { addUser, updateUser, delUser, getList, addTags } from '@/server'
const isShowTag = ref<boolean>(false)
const tags = ref<string[]>([])
const total = ref<number>(0)
const row = ref<{
id?: number,
name?: string,
desc?: string,
createTime?: Date
}>({})
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<boolean>(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: any) => {
dialogVisible.value = true;
Object.assign(form, row)
}
//关闭弹框
const close = () => {
dialogVisible.value = false;
}
</script>
<style lang='less'>
* {
padding: 0;
margin: 0;
}
html,
body {
background: #ccc;
}
.wraps {
height: 100vh;
padding: 30px;
}
</style>

新增了一个接口
import axios from 'axios'
axios.defaults.baseURL = 'http://localhost:3000'
export const addUser = (data) => axios.post('/user',data).then(res => res.data)
export const getList = (data) => axios.get('/user',{params:data}).then(res => res.data)
export const delUser = (data) => axios.delete(`/user/${data.id}`).then(res => res.data)
export const updateUser = (data) => axios.patch(`/user/${data.id}`,data).then(res => res.data)
//添加tag
export const addTags = (data) => axios.post(`/user/add/tags`,data).then(res => res.data)
后端Nestjs
1.新建一个 tags.entity.ts
定义Tags的数据表
import { Column, Entity, PrimaryGeneratedColumn, BeforeInsert, CreateDateColumn, Generated, OneToOne, 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
}
Modal 需要关联tag表
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';
// import { example } from './entities/tags.entity';
@Module({
imports:[TypeOrmModule.forFeature([User,Tags])],
controllers: [UserController],
providers: [UserService]
})
export class UserModule {}
然后user表跟tags表进行关联
import { Column, Entity, PrimaryGeneratedColumn, BeforeInsert, CreateDateColumn, Generated, OneToOne, JoinColumn, 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[]
// example: example
}
这儿我们解释一下 OneToMany 和 ManyToOne的用法
对于用户来说一个用户可以拥有多个tag 他们的关系是一对多 OneToMany
对于tag来说他们是多个tag指定单个用户 所以是 ManyToOne

OneToMany 接受两个参数
第一个参数是个函数返回关联的类 所以在user表关联tag
第二个参数 创建双向关系
ManyToOne 用法一样
@OneToMany(() => Tags, (tags) => tags.user)
保存该关系
沿用上一章的代码增加Controller 增加 addTags
import { Controller, Get, Post, Body, Patch, Param, Delete, Query } from '@nestjs/common';
import { UserService } from './user.service';
import { CreateUserDto } from './dto/create-user.dto';
import { UpdateUserDto } from './dto/update-user.dto';
@Controller('user')
export class UserController {
constructor(private readonly userService: UserService) {}
@Post('/add/tags')
addTags (@Body() params:{tags:string[],userId:number}) {
return this.userService.addTags(params)
}
@Post()
create(@Body() createUserDto: CreateUserDto) {
return this.userService.create(createUserDto);
}
@Get()
findAll(@Query() query:{keyWord:string,page:number,pageSize:number}) {
return this.userService.findAll(query);
}
@Patch(':id')
update(@Param('id') id: string, @Body() updateUserDto: UpdateUserDto) {
return this.userService.update(+id, updateUserDto);
}
@Delete(':id')
remove(@Param('id') id: string) {
return this.userService.remove(+id);
}
}
service 增加 addTags 方法
import { Injectable } from '@nestjs/common';
import { CreateUserDto } from './dto/create-user.dto';
import { UpdateUserDto } from './dto/update-user.dto';
import { Repository, Like } from 'typeorm';
import { InjectRepository } from '@nestjs/typeorm';
import { User } from './entities/user.entity';
import { Tags } from './entities/tags.entity';
// import { example } from './entities/tags.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++) {
let 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 create(createUserDto: CreateUserDto) {
const data = new User()
// const ex = new example()
data.name = createUserDto.name
data.desc = createUserDto.desc
// await this.example.save(ex)
return this.user.save(data)
}
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
}
}
update(id: number, updateUserDto: UpdateUserDto) {
return this.user.update(id, updateUserDto)
}
remove(id: number) {
return this.user.delete(id)
}
}

如果需要联合查询需要增加 relations 注意看上面的代码
我的问题的一个例子是体育游戏。一场体育比赛有两支球队,一支主队和一支客队。我的事件记录模型如下:classTeam"Team"has_one:away_team,:class_name=>"Team"end我希望能够通过游戏访问一个团队,例如:Game.find(1).home_team但我收到一个单元化常量错误:Game::team。谁能告诉我我做错了什么?谢谢, 最佳答案 如果Gamehas_one:team那么Rails假设您的teams表有一个game_id列。不过,您想要的是games表有一个team_id列,在这种情况下
📢博客主页:https://blog.csdn.net/weixin_43197380📢欢迎点赞👍收藏⭐留言📝如有错误敬请指正!📢本文由Loewen丶原创,首发于CSDN,转载注明出处🙉📢现在的付出,都会是一种沉淀,只为让你成为更好的人✨文章预览:一.分辨率(Resolution)1、工业相机的分辨率是如何定义的?2、工业相机的分辨率是如何选择的?二.精度(Accuracy)1、像素精度(PixelAccuracy)2、定位精度和重复定位精度(RepeatPrecision)三.公差(Tolerance)四.课后作业(Post-ClassExercises)视觉行业的初学者,甚至是做了1~2年
有没有办法跳过CSV文件的第一行,让第二行作为标题?我有一个CSV文件,第一行是日期,第二行是标题,所以我需要能够在遍历它时跳过第一行。我尝试使用slice但它会将CSV转换为数组,我真的很想将其读取为CSV,以便我可以利用header。 最佳答案 根据您的数据,您可以使用另一种方法和skip_lines-option此示例跳过所有以#开头的行require'csv'CSV.parse(DATA.read,:col_sep=>';',:headers=>true,:skip_lines=>/^#/#Markcomments!)do|
我想合并多个事件记录关系例如,apple_companies=Company.where("namelike?","%apple%")banana_companies=Company.where("namelike?","%banana%")我想结合这两个关系。不是合并,合并是apple_companies.merge(banana_companies)=>Company.where("namelike?andnamelike?","%apple%","%banana%")我要Company.where("名字像?还是名字像?","%apple%","%banana%")之后,我会写代
我有一个简单的问题,与关联有关。我有一个书的模型,它有_onereservation。预订属于_书本。我想在预订Controller的创建方法中确保在预订时没有预订一本书。换句话说,我需要检查该书是否存在任何其他预订。我该怎么做?编辑:Aaa我做到了,感谢大家的提示,学到了一些新东西。当我尝试提供的解决方案时,出现no_method错误或nil_class等。这让我开始思考,我尝试处理的对象根本不存在。Krule给了我使用book.find的想法,所以我尝试使用它。最终我得到了它的工作:book=Book.find_by_id(reservation_params[:book_id])
我有一组名为Tasks和Posts的资源,它们之间存在has_and_belongs_to_many(HABTM)关系。还有一个连接它们的值的连接表。create_table'posts_tasks',:id=>falsedo|t|t.column:post_id,:integert.column:task_id,:integerend所以我的问题是如何检查特定任务的ID是否存在于从@post.tasks创建的数组中?irb(main):011:0>@post=Post.find(1)=>#@post.tasks=>[#,#]所以我的问题是,@post.tasks中是否存在"@task
根据我目前的理解,如果我必须描述Rails应用程序的各个组件如何协同工作以响应请求,我会说以下内容:1)路由确定哪些请求URL映射到哪些Controller方法。2)Controller方法从模型中获取信息并将该信息(以全局变量的形式)传递给相应的View模板。3)View模板使用存储在全局变量中的数据来构造最终响应。在上面的解释中,几个组件之间的关系是明确的,不可否认的;即:1)路由和Controller方法2)Controller方法和View模板其实上面的关系是一对一的。但是,模型类与其相邻组件类型(即Controller)的关系并不明确。是的,Controller从模型中检索信
我在目录“/home/enterprise/pkg”中有一个本地gem(enterprise-0.0.1.gem)。它依赖于active_directorygem(v1.5.5),这是在它的enterprise.gemspec文件中指定的,如下所示:-gem.add_dependency("active_directory")在我的应用程序的Gemfile中,我添加了以下行:-gem'enterprise','0.0.1',path=>'/home/enterprise/pkg'当我做的时候bundleinstall在我的应用程序的源目录中,只安装了企业gem。因此,我遇到了引用act
使用method_missing时在Ruby中,它是almostalwaysagoodidea定义respond_to_missing?respond_to_missing?接受两个参数;我们正在检查的方法的名称(symbol),以及一个指示我们是否应该在检查中包含私有(private)方法的bool值(include_all)。现在我感到困惑的是:method_missing不接受任何可能指示它是否应该调用私有(private)方法的参数,如respond_to_missing?做。此外,method_missing无论原始方法调用是在公共(public)上下文还是私有(privat
我正在构建这个图书馆应用程序,它有3个类。国家、图书馆和书籍。国家有许多图书馆,图书馆属于一个国家。图书馆有很多书,书是嵌入图书馆的。但是,当我执行此auto_pick_job时,我们到达top_free_book并调用library.state。由于某种原因,library.state为nil。我希望恢复状态但没有骰子。我调用和创建库的方式如下。所以图书馆将永远属于一个现有的国家。state=Stats.find(x)library=state.libaries.new(info)library.save_optimistic!我也很感激使用Struct的关系帮助。classStat