您的位置:首页 > 财经 > 产业 > 新公司需要做网站_健康义乌app_2022世界足球排行榜_石家庄网站建设案例

新公司需要做网站_健康义乌app_2022世界足球排行榜_石家庄网站建设案例

2025/4/27 3:30:26 来源:https://blog.csdn.net/qq_45902692/article/details/147355615  浏览:    关键词:新公司需要做网站_健康义乌app_2022世界足球排行榜_石家庄网站建设案例
新公司需要做网站_健康义乌app_2022世界足球排行榜_石家庄网站建设案例

个人简介

👀个人主页: 前端杂货铺
🙋‍♂️学习方向: 主攻前端方向,正逐渐往全干发展
📃个人状态: 研发工程师,现效力于中国工业软件事业
🚀人生格言: 积跬步至千里,积小流成江海
🥇推荐学习:🍍前端面试宝典 🎨100个小功能 🍉Vue2 🍋Vue3 🍓Vue2/3项目实战 🥝Node.js实战 🍒Three.js

🌕个人推广:每篇文章最下方都有加入方式,旨在交流学习&资源分享,快加入进来吧

内容参考链接
NestJS(一)Docker入门
NestJS(二)NestJS——创建项目、编写User模块
NestJS(三)TypeScript入门
NestJS(四)编程思想——FP、OOP、FRP、AOP、IOC、DI、MVC、DTO、DAO
NestJS(五)NestJS——多环境配置方案(dotenv、config、@nestjs/config、joi配置校验)
NestJS(六)NestJS——使用TypeORM连接MySQL数据库(Docker拉取镜像、多环境适配)

文章目录

    • 使用 TypeORM 形成数据库
    • CRUD 操作
    • 一对一、一对多查询
    • QueryBuilder
    • 总结

使用 TypeORM 形成数据库

GitHub 提交记录

如下图所示为一个用户系统。users用户表、profile个人信息表、logs日志表、roles角色表。

一对一关系:一个用户对应一个个人信息
一对多关系:一个用户对应多个日志,多个日志对应一个用户
多对多关系:一个用户对应多个角色,一个角色对应多个用户

对于人和角色的关系,若使用一对多(One-to-Many)的话会存在缺陷:
若在 person 表中添加 role_id 字段,则每个人物只能绑定一个角色。
若在 role 表中添加 person_id 字段,则每个角色只能绑定一个人物。
无法满足双向的“多对多”需求。

在这里插入图片描述

参照目录如下:

在这里插入图片描述

创建 user.entity.ts 文件,存放用户的实体类。

import { Logs } from "src/logs/logs.entity"; // 导入日志实体
import { Roles } from "src/roles/roles.entity"; // 导入角色实体
import {Column,Entity,JoinTable,ManyToMany,OneToMany,PrimaryGeneratedColumn,
} from "typeorm"; // 从 TypeORM 导入装饰器/*** 用户实体类,映射到数据库中的 `User` 表*/
@Entity()
export class User {/*** 主键字段,自动生成唯一 ID*/@PrimaryGeneratedColumn()id: number; // 主键/*** 用户名字段*/@Column()username: string;/*** 密码字段*/@Column()password: string;/*** 一对多关系:* - 一个用户可以有多个日志* - `Logs` 表中的 `user` 字段表示反向关系*/@OneToMany(() => Logs, (logs) => logs.user)logs: Logs[]; // 一对多关系,一个用户对应多个日志/*** 多对多关系:* - 一个用户可以拥有多个角色* - 使用 `user_roles` 作为连接表* - `Roles` 表中的 `users` 字段表示反向关系*/@ManyToMany(() => Roles, (roles) => roles.users)@JoinTable({ name: "user_roles" }) // 指定连接表的名称为 `user_roles`roles: Roles[]; // 多对多关系,一个用户可能拥有多个角色
}

创建 profile.entity.ts 文件,存放个人资料的实体类。

import {Column,Entity,JoinColumn,OneToOne,PrimaryGeneratedColumn,
} from "typeorm";
import { User } from "./user.entity"; // 导入用户实体/*** 个人资料实体类,映射到数据库中的 `Profile` 表*/
@Entity()
export class Profile {/*** 主键字段,自动生成唯一 ID*/@PrimaryGeneratedColumn()id: number; // 主键/*** 性别字段* - 使用数字表示性别(如 0 表示未知,1 表示男性,2 表示女性)*/@Column()gender: number;/*** 头像字段* - 存储用户头像的 URL 或路径*/@Column()photo: string;/*** 地址字段* - 存储用户的居住地址*/@Column()address: string;/*** 一对一关系:* - 一个用户对应一个个人资料* - `user` 字段表示与 `User` 实体的关联* - 使用 `@JoinColumn` 指定外键关系*/@OneToOne(() => User) // 定义一对一关系@JoinColumn() // 指定外键关联,外键会存储在 `Profile` 表中user: User; // 关联的用户实体
}

创建 logs.entity.ts 文件,存放日志的实体类。

import { User } from "src/user/user.entity"; // 导入用户实体
import {Column,Entity,JoinColumn,ManyToOne,PrimaryGeneratedColumn,
} from "typeorm"; // 从 TypeORM 导入装饰器/*** 日志实体类,映射到数据库中的 `Logs` 表*/
@Entity()
export class Logs {/*** 主键字段,自动生成唯一 ID*/@PrimaryGeneratedColumn()id: number; // 主键/*** 请求路径字段* - 存储 API 请求的路径*/@Column()path: string;/*** 请求方法字段* - 存储 HTTP 请求方法(如 GET、POST 等)*/@Column()method: string;/*** 请求数据字段* - 存储请求的参数或数据*/@Column()data: string;/*** 请求结果字段* - 存储请求的响应状态码(如 200、404 等)*/@Column()result: number;/*** 多对一关系:* - 多个日志对应一个用户* - `user` 字段表示与 `User` 实体的关联* - 使用 `@JoinColumn` 指定外键关系*/@ManyToOne(() => User, (user) => user.logs) // 定义多对一关系@JoinColumn() // 指定外键关联,外键会存储在 `Logs` 表中user: User; // 关联的用户实体
}

创建 roles.entity.ts 文件,存放角色的实体类。

import { User } from "src/user/user.entity"; // 导入用户实体
import {Column,Entity,ManyToMany,PrimaryGeneratedColumn,
} from "typeorm"; // 从 TypeORM 导入装饰器/*** 角色实体类,映射到数据库中的 `Roles` 表*/
@Entity()
export class Roles {/*** 主键字段,自动生成唯一 ID*/@PrimaryGeneratedColumn()id: number; // 主键/*** 角色名称字段* - 存储角色的名称(如管理员、用户等)*/@Column()name: string;/*** 多对多关系:* - 一个角色可以分配给多个用户* - `users` 字段表示与 `User` 实体的关联* - 反向关系由 `User` 实体中的 `roles` 字段定义*/@ManyToMany(() => User, (user) => user.roles) // 定义多对多关系users: User[]; // 多对多关系,一个角色可能由多个用户拥有
}

app.module.ts 文件中添加相应实体。

在这里插入图片描述

至此,数据库的表格关系创建完成。


CRUD 操作

GitHub 操作记录

接下来,我们实现基本的 增删改查 操作。

user.controller.ts 文件中添加相应的路由。

import { Controller, Get, Post } from "@nestjs/common"; // 导入控制器和 HTTP 请求装饰器
import { UserService } from "./user.service"; // 导入用户服务
import { User } from "./user.entity"; // 导入用户实体/*** 用户控制器类* - 定义与用户相关的 HTTP 路由和处理逻辑* - 使用 `UserService` 提供的业务逻辑操作用户数据*/
@Controller("user") // 定义控制器的路由前缀为 "user"
export class UserController {/*** 构造函数* - 注入用户服务* @param userService 用户服务*/constructor(private userService: UserService) {}/*** 获取所有用户* - 路由:GET /user/getAll* @returns 所有用户的列表*/@Get("getAll")getUsers(): any {return this.userService.findAll(); // 调用服务层方法查询所有用户}/*** 获取单个用户* - 路由:GET /user/getOne* - 示例中固定查询用户名为 "test" 的用户* @returns 匹配的用户对象或 null*/@Get("getOne")getOneUser(): any {const username = "test"; // 示例用户名return this.userService.find(username); // 调用服务层方法查询用户}/*** 添加新用户* - 路由:POST /user/add* - 示例中固定添加用户名为 "test" 的用户* @returns 保存后的用户对象*/@Post("add")addUser(): any {const user = { username: "test", password: "123456" } as User; // 示例用户数据return this.userService.create(user); // 调用服务层方法创建用户}/*** 更新用户信息* - 路由:POST /user/update* - 示例中固定更新 ID 为 1 的用户* @returns 更新结果*/@Post("update")updateUser(): any {const id = 1; // 示例用户 IDconst user = { username: "zahuopu", password: "654321" } as User; // 示例更新数据return this.userService.update(id, user); // 调用服务层方法更新用户}/*** 删除用户* - 路由:GET /user/remove* - 示例中固定删除 ID 为 1 的用户* @returns 删除结果*/@Get("remove")removeUser(): any {const id = 1; // 示例用户 IDreturn this.userService.remove(id); // 调用服务层方法删除用户}
}

user.service.ts 文件中进行相关业务操作,操作数据库。

import { Injectable } from "@nestjs/common"; // 导入 Injectable 装饰器,用于标记服务类
import { InjectRepository } from "@nestjs/typeorm"; // 用于注入 TypeORM 仓库
import { Repository } from "typeorm"; // 导入 TypeORM 的 Repository 类
import { User } from "./user.entity"; // 导入用户实体/*** 用户服务类* - 提供用户相关的业务逻辑* - 使用 TypeORM 操作数据库中的 `User` 表*/
@Injectable()
export class UserService {/*** 构造函数* - 注入用户实体的 TypeORM 仓库* @param userRepository 用户实体的仓库*/constructor(@InjectRepository(User) private readonly userRepository: Repository<User>) {}/*** 查询所有用户* @returns 所有用户的列表*/findAll() {return this.userRepository.find(); // 使用 TypeORM 的 `find` 方法查询所有用户}/*** 根据用户名查询用户* @param username 用户名* @returns 匹配的用户对象或 null*/find(username: string) {return this.userRepository.findOne({ where: { username } }); // 根据条件查询单个用户}/*** 根据 ID 查询用户* @param id 用户 ID* @returns 匹配的用户对象或 null*/findOne(id: number) {return this.userRepository.findOne({ where: { id } }); // 根据 ID 查询单个用户}/*** 创建新用户* @param user 用户对象* @returns 保存后的用户对象*/async create(user: User) {const newUser = await this.userRepository.create(user); // 创建用户实例return this.userRepository.save(newUser); // 保存用户到数据库}/*** 更新用户信息* @param id 用户 ID* @param user 部分用户信息* @returns 更新结果*/update(id: number, user: Partial<User>) {return this.userRepository.update(id, user); // 根据 ID 更新用户信息}/*** 删除用户* @param id 用户 ID* @returns 删除结果*/remove(id: number) {return this.userRepository.delete(id); // 根据 ID 删除用户}
}

一对一、一对多查询

我们打开数据库操作网址,对 userId 为 2 的用户添加一条 profile 个人信息及两条 logs 日志。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

修改 user.entity.ts 文件,完善对应关系。

  /*** 一对一关系:* - 一个用户对应一个个人资料* - `Profile` 表中的 `user` 字段表示反向关系*/@OneToOne(() => Profile, (profile) => profile.user)profile: Profile; // 一对一关系,一个用户对应一个个人资料

修改 user.module.ts 文件,注册 Logs 实体(这是一种不规范的写法,方便测试先这么写)

imports: [TypeOrmModule.forFeature([User, Logs])], // 注册 User、Logs 实体

修改 user.service.ts 文件,添加查询用户资料和查询用户日志的逻辑。

 /*** 查询用户的个人资料* @param id 用户 ID* @param profile 个人资料对象* @returns 保存后的个人资料对象*/findProfile(id: number) {return this.userRepository.findOne({where: { id },relations: {profile: true, // 关联查询个人资料},});}/*** 查询用户的日志* @param id 用户 ID* @returns 用户的日志列表*/async findUserLogs(id: number) {const user = await this.findOne(id);return this.logsRepository.find({where: { user }, // 根据用户 ID 查询日志relations: {user: true, // 关联查询用户},});}

相应的,我们修改 user.controller.ts 文件,添加相应的路由。

  /*** 获取用户的个人资料* - 路由:GET /user/profile* @returns 用户的个人资料*/@Get("profile")getUserProfile(): any {return this.userService.findProfile(2); // 调用服务层方法查询用户个人资料}/*** 获取用户的日志* @returns 用户的日志* - 路由:GET /user/logs* @description 获取用户的日志信息*/@Get("logs")getUserLogs(): any {return this.userService.findUserLogs(2); // 调用服务层方法查询用户日志}

在这里插入图片描述

在这里插入图片描述


QueryBuilder

TypeORM 中文网 - QueryBuilder介绍

GitHub 提交记录

QueryBuilder 是 TypeORM 最强大的功能之一,它允许你使用优雅便捷的语法构建 SQL 查询,执行并获得自动转换的字体。

接下来,我们针对于 logs 表格进行新建数据,详情如下:

在这里插入图片描述

修改 user.service.ts 文件,添加查询用户日志的逻辑。

  /*** 查询用户的日志* @param id 用户 ID* @returns 用户的日志*/async findLogsByGroup(id: number) {return this.logsRepository.createQueryBuilder("logs") // 创建查询构造器,指定查询的表别名为 "logs".select("logs.result", "result") // 选择日志的结果字段,并将其别名为 "result".addSelect('Count("logs.result")', "count") // 统计每种结果的数量,并将其别名为 "count".leftJoinAndSelect("logs.user", "user") // 左连接 "logs" 表中的 "user" 字段,指定别名为 "user".where("user.id = :id", { id }) // 添加条件,筛选出指定用户 ID 的日志.groupBy("logs.result") // 按 "logs.result" 字段分组.orderBy("result", "DESC") // 按 "result" 字段降序排序.offset(2) // 跳过前两个分组结果.addOrderBy("count", "DESC") // 按 "count" 字段降序排序.limit(3) // 限制返回的分组数量为 3.getRawMany(); // 执行查询并返回原始结果数组}

相应的,我们修改 user.controller.ts 文件,添加相应路由。

  /** 获取用户的日志* @returns 用户的日志* - 路由:GET /user/logsByGroup* @description 获取用户的日志信息*/@Get("logsByGroup")async getLogsByGroup(): Promise<any> {const res = await this.userService.findLogsByGroup(2); // 调用服务层方法查询用户日志按组// 处理查询结果return res.map((o) => ({result: o.result,count: o.count,}));}

在这里插入图片描述

修改 app.module.ts 文件,在开发环境下打印全部日志。

logging: process.env.NODE_ENV === "development", // 日志

这样,在发请求的时候我们就可以在终端看到相关 sql 语句。

在这里插入图片描述


总结

本篇文章,我们学习了如何使用TypeORM操作数据库,如何进行增删改查操作及关联查询,并使用 QueryBuilder 完成了一些 sql 查询。

好啦,本篇文章到这里就要和大家说再见啦,祝你这篇文章阅读愉快,你下篇文章的阅读愉快留着我下篇文章再祝!


参考资料:

  1. DeepSeek
  2. NestJS 从入门到实战

在这里插入图片描述

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com