nestjs 全栈进阶--typeorm

306 阅读6分钟

1. 介绍

TypeORM 是一个用于 Node.js 的 ORM(Object-Relational Mapping,对象关系映射)库,它提供了一种将 JavaScript 对象映射到数据库表的方式。这意味着你可以使用 JavaScript 对象和 TypeScript 类来与数据库进行交互,而不必编写原始的 SQL 语句。

以下是 TypeORM 的一些关键特性:

  1. 类型安全:由于 TypeORM 支持 TypeScript,它允许你在开发时获得类型检查的好处。
  2. 数据库支持:TypeORM 支持多种数据库系统,包括 MySQL, PostgreSQL, SQLite, Microsoft SQL Server, Oracle, 和 MongoDB(通过一个单独的 MongoDB 驱动)。
  3. 实体和关系:你可以定义实体类来表示数据库中的表,并且可以轻松地定义实体之间的关系,如一对一、一对多和多对多。
  4. 高级功能:TypeORM 提供了事务、迁移、复用数据库连接、复杂查询等高级功能。
  5. 查询构建器:它提供了一个强大的查询构建器,允许你构建复杂的查询而不必手写 SQL。
  6. 懒加载:支持懒加载和急切加载,以优化应用程序的性能。
  7. 可定制性:TypeORM 允许你自定义实体的列映射、表名、列名等。
  8. 活跃记录模式:TypeORM 支持数据映射模式,包括数据映射和活跃记录模式。
  9. 装饰器:使用 TypeScript 的装饰器语法,TypeORM 允许你以声明式的方式定义实体和列。
  10. 集成:TypeORM 可以很容易地集成到现有的 Node.js 应用程序中,并且与许多流行的框架(如 Express.js)协同工作。

TypeORM 的使用通常涉及以下步骤:

  • 定义实体:创建 TypeScript 类,使用 TypeORM 提供的装饰器来定义实体属性和数据库表的映射关系。
  • 建立连接:配置并建立与数据库的连接。
  • 执行操作:使用 TypeORM 的 API 来执行 CRUD(创建、读取、更新、删除)操作。
  • 迁移:使用迁移来自动更新数据库结构以匹配你的实体定义。

TypeORM 是一个功能强大的库,适用于希望在 Node.js 应用程序中使用 ORM 功能的开发者。

2. 项目创建

2.1. 创建一个typeorm项目

npx typeorm init --name MyProject --database mysql

他生成的项目结构

2.2. 创建个容器

services:
  mysql8:
    image: mysql:8.0
    restart: always
    # 设置默认的认证插件为mysql_native_password
    command: --default-authentication-plugin=mysql_native_password
    environment:
      MYSQL_ROOT_PASSWORD: root
    ports:
      # 映射为 13311端口
      - '13311:3306'

在当前目录下执行docker-compose up,然后打开你的Docker Desktop,你就会发现,多了一个容器,绿色代表正常运行

2.3. 创建一个数据库

我这台电脑上安装的可视化工具是DBeaver,这里我就用DBeaver给大家演示(后面如果我在另外一台电脑上操作的话,会用navicat)

点击这个数据库,在点击 新建数据库连接

选择mysql,在下一步

注意:这个端口,它默认是3306,但是我们上面写的那个容器配置,是映射到13311的(主要是我电脑会开很多mysql配置,所以我就重新映射了端口),密码也是我们上面自己写的那个密码,点击测试,没问题就点击完成。

鼠标右击这个数据库,点击新建数据库

输入个数据库名,其他就 用默认的就行,点击确定,数据库就创建成功了

3. 创建表

我们现在回到我们的项目中

pnpm install mysql2

pnpm start

他就会给我们去创建表

这就是他生成的表和数据(记得在表上鼠标右键,然后点刷新)

他建表的依据是根据我们实体来的

默认生成的数据是在index.ts中,它给我们写的

4. 创建实体

实体是映射到数据库表(或使用 MongoDB 时的集合)的类。你可以通过定义一个新类来创建一个实体,并用 @Entity() 标记它:

我们新建一个实体,来看看我们如何写一个建表的实体类

import { Entity, PrimaryGeneratedColumn, Column } from "typeorm"

// @Entity指定它是一个 Entity
@Entity({
    name: 't_aaa' // 自己定义表名
})
export class Aaa {

    // @PrimaryGeneratedColumn()指定主键,并且自动生成
    @PrimaryGeneratedColumn({
        comment: '主键id' // 添加注释
    })
    id: number

    // @Column() 映射属性和字段的对应关系
    @Column({
        name: 'user_name', // 自定义字段名
        unique: true, // 添加唯一约束
        type: 'varchar', // 设置字段类型
        length: 20, // 设置字段长度
        comment: '姓名' // 添加注释
    })
    name: string

    @Column({
        type: 'double',
    })
    height: number

}

type 数据库里的数据类型

我们再去引用下Aaa

pnpm start

更多实体内容请参考:typeorm.nodejs.cn/entities

5. crud

5.1. 增

save的方式

pnpm start

批量新增

inset 方式

5.2. 改

save的方式

我们的save不仅可以新增还可以修改,你指定了主键,他就变成修改

运行后,可以看到他会先查询在修改。

那我们给个不存在的id呢?

可以看到id没在数据库里时,他就会变成新增

批量修改

update的方式

那我们给个不存在的id呢?

可以看到这种是不会给我们新增进去的

批量修改

5.3. 查

查单个

还可以

还可以查不到时就报错

他找不到时会抛一个 EntityNotFoundError 的异常

查所有

条件查询多个

查数量

你还可以指定条件

5.4. 删

批量删

remove的删除

5.5. 执行原生sql

5.6. queryBuilder

import { AppDataSource } from "./data-source"
import { User } from "./entity/User"

AppDataSource.initialize().then(async () => {
    // createQueryBuilder() 是 TypeORM 提供的一个方法,用于创建一个新的查询构建器实例,允许你以一种流畅和声明式的方式构建 SQL 查询。
    const queryBuilder = await AppDataSource.manager.createQueryBuilder();

    // select("user") 指定了你想从数据库中选择的字段
    // from(User, "user") 指定了查询的来源,即你想从哪个实体(或表)中选择数据。User 是实体类的名称,而 "user" 是为这个实体指定的别名。
    // where("user.age = :age", { age: 26 }) 定义了一个查询条件,即选择 age 字段等于 26 的记录。:age 是一个参数占位符,后面的对象 { age: 26 } 提供了实际的参数值。
    // getOne() 是查询构建器的一个方法,用于执行构建的查询并返回结果。由于使用了 getOne(),所以查询结果应该是单个对象,而不是一个对象数组。
    const user = await queryBuilder.select("user")
        .from(User, "user")
        .where("user.age = :age", { age: 26 })
        .getOne();

    console.log(user);
    

}).catch(error => console.log(error))

5.7. getRepository

之前我们都是通过参数指定的实体,如:

我们还可以 使用 getRepository

5.8. 开启事务