小满nestjs(第二十七章 nestjs typeOrm关系)

news2025/1/9 15:20:05

在我们开始的过程中,肯定不会把数据存在一个表里面,我们会进行分表,把数据分开存,然后通过关联关系,联合查询。

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 注意看上面的代码

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/102157.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

腾讯安全联合发布《2022游戏安全白皮书》:外挂对抗仍然激烈

2022年以来&#xff0c;各类游戏安全事件的发生给不断影响着游戏生态的健康发展。同时&#xff0c;随着游戏行业数字化进程的加快&#xff0c;以及游戏全球化布局的不断推进&#xff0c;游戏厂商对于游戏安全的投入越来越大&#xff0c;掌握最新的行业安全态势有利于其安全防护…

外汇天眼:WiKiEXPO亮相香港亚洲博览馆,史上最强大咖阵容坐镇

凛冬已至&#xff0c;在这个寒冷的冬天&#xff0c;WikiGlobal将于2022年12月16日至17日早9:00--晚18:00在香港的亚洲国际博览馆举办为期两天的“Wiki Finance EXPO Asia 2022”。目前展会已拉开帷幕。  此次展会展厅面积高达5000多平方米&#xff0c;经过WiKiEXPO科学的规划和…

【数据结构】线性表之单链表

目录 一、链表的概念 1、概念 2、分类 3、重点 二、单链表模拟实现 1、准备 2、头插法 3、尾插法 4、指定下标插入 5、遍历 6、删除第一次出现的元素key 7、删除所有的key 8、双指针删除所有的key 一、链表的概念 1、概念 是一种物理存储结构上非连续的存储结构&a…

PS-历史记录

目录 哪里能找到【历史记录】面板 1、窗口→历史记录 2、编辑→清理→历史记录 还原 1、点击【历史记录】面板 快捷键 【ctrlz】 【shiftctrlz】 从当前状态创建新文档 创建新快照 给快照起名 1、右击你要创建快照的步骤 2、点击面板菜单 3、先按住alt不动&#…

Java 对象和类

Java作为一种面向对象语言。支持以下基本概念&#xff1a; 多态继承封装抽象类对象实例方法重载 本节我们重点研究对象和类的概念。 对象&#xff1a;对象是类的一个实例&#xff08;对象不是找个女朋友&#xff09;&#xff0c;有状态和行为。例如&#xff0c;一条狗是一个对…

猿如意|chat GPT测评

文章目录猿如意猿如意传送门猿如意个人使用感受好的一面&#xff1a;可以改进的一面:什么是猿如意chat GPT测评chat GPT使用过程使用场景描述&#xff1a;问题1问题2问题3问题4&#xff1a;问题5&#xff1a;主观感受&#xff1a;认为此功能不足的地方&#xff1a;对此功能的期…

学习编程的过程中可能会走哪些弯路,有哪些经验可以参考?

很多人学习编程, 走的弯路可以总结为以下几点: 一言不合找视频&#xff0c;几十集视频刷半年。 很多人学习编程的时候&#xff0c;喜欢看视频学&#xff0c;我这里总结一下看视频学习编程的弊端。 1. 完善的视频资源往往稍稍过时&#xff0c;比如你会发现很多java的教学视频…

产品设计市场调研有哪些特点?

产品市场种类繁多&#xff0c;变化无常&#xff0c;消费者需求各异。在工业设计之初&#xff0c;需要对行业和区域环境进行调查分析&#xff0c;深入了解市场情况、市场供求关系、客户引导、趋势等&#xff0c;客观合理地对新产品进行适当定位。只有有了正确的新产品概念规划方…

三方接口签名验签简易设计与实现

本人水平有限&#xff0c;对密码学的理解相当浅显。错误与疏漏&#xff0c;欢迎各位指正。 〇、写在前面 接口安全防护是个永恒的话题&#xff0c;提供给前端的接口需要登录&#xff0c;提供给服务的接口(下文简称"三方接口")也需要鉴权&#xff1b;当前大环境下,ht…

chatgpt教我内存对齐,对齐了但没完全对齐?

文章目录内存对齐关于chatgpt的回答总结内存对齐 关于chatgpt的回答 我与chatgpt的对话如下&#xff1a; 我现在来描述与总结上述对话都干了啥以及我为什么要问这个。 我本来是在学习rapidjson源码里面的内存池实现&#xff0c;然后 RAPIDJSON_ALIGN 没有看懂&#xff0c;所…

JSP课设:家庭相册管理系统(附源码+调试)

JSP家庭相册管理系统 &#xff08;1&#xff09;登录模块&#xff1a;分为普通用户和管理员两种角色&#xff1b; &#xff08;2&#xff09;普通用户模块&#xff1a;相册管理&#xff1a;用户可以对自己相册进行编辑&#xff0c;可以进行批量删除相册、新增相册、编辑相册以…

【Golang】案例为基浅谈Go的变量与常量

&#x1f4d3;推荐网站(不断完善中)&#xff1a;个人博客 &#x1f4cc;个人主页&#xff1a;个人主页 &#x1f449;相关专栏&#xff1a;CSDN专栏、个人专栏 &#x1f3dd;立志赚钱&#xff0c;干活想躺&#xff0c;瞎分享的摸鱼工程师一枚 &#x1f352;前言 在上一篇文章中…

Python图像识别实战(三):基于OpenCV实现批量单图像超分辨重建(附源码和实现效果)

前面我介绍了可视化的一些方法以及机器学习在预测方面的应用&#xff0c;分为分类问题&#xff08;预测值是离散型&#xff09;和回归问题&#xff08;预测值是连续型&#xff09;&#xff08;具体见之前的文章&#xff09;。 从本期开始&#xff0c;我将做一个关于图像识别的…

“命悬一线”复试上岸浙大MBA的经验分享~

作为去年踩线上岸浙大MBA的幸运者&#xff0c;希望自己的一些经历和经验能够帮助到今年的考生。因为去年在联考初试准备的时间不是很充分&#xff0c;加上在职工作相对比较忙&#xff0c;真正能用到学习上时间真的不多。笔试成绩只拿到191分&#xff0c;在去年的复试考生里算是…

Qt+C++基本绘图(画线,画圆,矩形, 撤销,重做)

程序示例精选 QtC基本绘图(画线&#xff0c;圆&#xff0c;矩形画线&#xff09; 如需安装运行环境或远程调试&#xff0c;见文章底部微信名片&#xff0c;由专业技术人员远程协助&#xff01; 前言 这篇博客针对《QtC基本绘图(画线&#xff0c;画圆&#xff0c;矩形, 撤销&am…

Redis常见面试题(四)

1、Redis有哪些淘汰策略? Redis目前有8种淘汰策略: 1&#xff09;Volatile-lru: 设置了过期时间的Key使用了LRU算法淘汰; 2&#xff09;Allkeys-lru: 所有key使用LRU算法; 3&#xff09;Volatile-lfu: 设置了过期时间的key使用了LFU算法淘汰; 4&#xff09;Allkeys-lfu: …

一文读懂页面布局

一. 前端布局 谈到浏览器页面&#xff0c;我们肯定是希望页面越美观越好&#xff0c;这样才能吸引用户点击。页面美观就自然需要用到各种布局&#xff0c;好的布局不仅能提高用户体验感留住用户&#xff0c;还能提高维护的效率。本文就列举一下常用的前端布局&#xff0c;并配上…

【MATLAB教程案例65】深度学习网络建模2,通过deepNetworkDesigner工具箱实现

欢迎订阅《FPGA学习入门100例教程》、《MATLAB学习入门100例教程》 目录 1.软件版本 2.分类识别数据库的应用

第八章练习题-2

第七题 答案 package com.hspedu.homework.homework07;public class HomeWork07 {public static void main(String[] args) {} } class Test{ //父类String name "Rose";Test(){System.out.println("Test");}Test(String name){this.name name;} } clas…

国考省考行测:标题选择题,仍然是考主旨,借助关联词、主体、结构、或对策分析法找正确的标题,通过偏颇,片面,无关,过重,空泛的方法排除错误选项

国考省考行测&#xff1a;标题选择题&#xff0c;仍然是考主旨&#xff0c;借助关联词、主体、结构、或对策分析法找正确的标题&#xff0c;通过偏颇&#xff0c;片面&#xff0c;无关&#xff0c;过重&#xff0c;空泛的方法排除错误选项 2022找工作是学历、能力和运气的超强…