TypeORM 是一个 ORM 框架,它可以运行在 NodeJS、Browser、Cordova、PhoneGap、Ionic、React Native、Expo 和 Electron 平台上,可以与 TypeScript 和 JavaScript (ES5,ES6,ES7,ES8)一起使用。
它的目标是始终支持最新的 JavaScript 特性并提供额外的特性以帮助你开发任何使用数据库的(不管是只有几张表的小型应用还是拥有多数据库的大型企业应用)应用程序。

实体

本系列只在 nestjs 下使用typrorm。

安装 typrorm 和 mysql

npm i @nestjs/typrorm typrorm mysql --save

nestjs中使用 ,连接mysql

app.module.ts 使用 TypeOrmModule 注册连接 mysql,填写mysql 配置

import { TypeOrmModule } from '@nestjs/typeorm';

@Module({
  imports: [
    TypeOrmModule.forRoot(
    {
      type: 'mysql',
      host: 'localhost',
      port: 3306,
      username: 'root',
      password: '123456',
      database: 'dengmi',
      entities: [__dirname + '/**/*.entity{.ts,.js}'],
      synchronize: true,
    },)
  ],
  controllers: [AppController, AdminController],
  providers: [AppService, ToolService, AdminService],
})
export class AppModule {}

注册实体models

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

在 src 目录下 新建entity 目录,新建 如 user.entity.ts,使用@Entity() 创建一个实体,@PrimaryGeneratedColumn() 创建主列 ,@Column() 创建列。

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

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

  @Column()
  firstName: string;

  @Column()
  lastName: string;

  @Column()
  age: number;
}

这将创建以下数据库表:

+-------------+--------------+----------------------------+
|                          user                           |
+-------------+--------------+----------------------------+
| id          | int(11)      | PRIMARY KEY AUTO_INCREMENT |
| firstName   | varchar(255) |                            |
| lastName    | varchar(255) |                            |
| isActive    | boolean      |                            |
+-------------+--------------+----------------------------+

基本实体由列和关系组成。 每个实体必须有一个主列(如果使用 MongoDB,则为 ObjectId 列)。

每个列可以获取任何类型的任何值。你也可以指定列类型。 如果未指定列类型,则将从属性类型自动推断。

实体列

@ Column 创建一个列,每个实体类属性都将映射到数据库表列。

@Entity()
export class User {
    @Column()
    firstName: string;

    @Column()
    lastName: string;
}

@PrimaryGeneratedColumn() 创建的主列,该值使用自动增量自动生成,它将使用auto-increment /serial /sequence创建int列(取决于数据库)。

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

@PrimaryGeneratedColumn("uuid") 创建的主列,该值将使用uuid自动生成。 Uuid 是一个独特的字符串 id,不必手动分配其值。

@Entity()
export class User {
    @PrimaryGeneratedColumn("uuid")
    id: string;
}

@PrimaryColumn() 复合主列

@Entity()
export class User {
    @PrimaryColumn()
    firstName: string;

    @PrimaryColumn()
    lastName: string;
}

特殊列

@CreateDateColumn() 创建的列,自动为实体插入日期。无需设置此列,该值将自动设置。

@Entity()
export class User {
    @CreateDateColumn()
    createTime:string
}

@UpdateDateColumn() 创建的列,在每次调用实体管理器或存储库的save时,自动更新实体日期。无需设置此列,该值将自动设置。

@Entity()
export class User {
    @UpdateDateColumn()
    updateTime:string
}

@VersionColumn() 创建的列,在每次调用实体管理器或存储库的save时自动增长实体版本(增量编号)。无需设置此列,该值将自动设置。

@Entity()
export class User {
    @VersionColumn()
    updateTime:string
}

空间列

详情见https://typeorm.io/#/entities/%E7%A9%BA%E9%97%B4%E5%88%97

列类型

TypeORM 支持所有最常用的数据库支持的列类型。 列类型是特定于数据库类型的 - 这为数据库架构提供了更大的灵活性。 你可以将列类型指定为@ Column的第一个参数 或者在@Column的列选项中指定,例如:

@Column("int")

@Column({ type: "int" })

也可以插入其他类型

@Column("varchar", { length: 200 })

@Column({ type: "int", length: 200 })

mysql/mariadb的列类型

int, tinyint, smallint, mediumint, bigint, float, double, dec, decimal, numeric, date, datetime, timestamp, time, year, char, varchar, nvarchar, text, tinytext, mediumtext, blob, longtext, tinyblob, mediumblob, longblob, enum, json, binary, geometry, point, linestring, polygon, multipoint, multilinestring, multipolygon, geometrycollection

enum 列类型

postgres和mysql都支持enum列类型,支持字符串,数字和异构枚举

使用typescript枚举:

export enum UserRole {
    ADMIN = "admin",
    EDITOR = "editor",
    GHOST = "ghost"
}

@Entity()
export class User {

    @PrimaryGeneratedColumn()
    id: number;

    @Column({
        type: "enum",
        enum: UserRole,
        default: UserRole.GHOST
    })
    role: UserRole

}

使用带枚举值的数组:

export type UserRoleType = "admin" | "editor" | "ghost",

@Entity()
export class User {

    @PrimaryGeneratedColumn()
    id: number;

    @Column({
        type: "enum",
        enum: ["admin", "editor", "ghost"],
        default: "ghost"
    })
    role: UserRoleType
}

simple-array的列类型

有一种称为simple-array的特殊列类型,它可以将原始数组值存储在单个字符串列中。 所有值都以逗号分隔。 例如:

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

    @Column("simple-array")
    names: string[];
}
const user = new User();
user.names = ["Alexander", "Alex", "Sasha", "Shurik"];

存储在单个数据库列中的Alexander,Alex,Sasha,Shurik值。 当你从数据库加载数据时,name 将作为 names 数组返回,就像之前存储它们一样。
注意:不能在值里面有任何逗号。

simple-json 列类型

还有一个名为simple-json的特殊列类型,它可以存储任何可以通过 JSON.stringify 存储在数据库中的值。 当你的数据库中没有 json 类型而你又想存储和加载对象,该类型就很有用了。 例如:

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

    @Column("simple-json")
    profile: { name: string; nickname: string };
}
const user = new User();
user.profile = { name: "John", nickname: "Malkovich" };

存储在单个数据库列中的{“name”:“John”,“nickname”:“Malkovich”}值 当你从数据库加载数据时,将通过 JSON.parse 返回 object/array/primitive。

具有生成值的列

你可以使用@Generated装饰器创建具有生成值的列。 例如:

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

    @Column()
    @Generated("uuid")
    uuid: string;
}

uuid值将自动生成并存储到数据库中。

除了"uuid"之外,还有"increment"生成类型,但是对于这种类型的生成,某些数据库平台存在一些限制(例如,某些数据库只能有一个增量列,或者其中一些需要增量才能成为主键)。

列选项

列选项定义实体列的其他选项。
你可以在@ Column上指定列选项:

@Column({
    type: "varchar",
    length: 150,
    unique: true,
    // ...
})
name: string;

ColumnOptions中可用选项列表:

  • type: ColumnType - 列类型。其中之一在上面.
  • name: string - 数据库表中的列名。

默认情况下,列名称是从属性的名称生成的。
你也可以通过指定自己的名称来更改它。

  • length: number - 列类型的长度。 例如,如果要创建varchar(150)类型,请指定列类型和长度选项。
  • width: number - 列类型的显示范围。 仅用于MySQL integer types
  • onUpdate: string - ON UPDATE触发器。 仅用于 MySQL.
  • nullable: boolean - 在数据库中使列NULLNOT NULL。 默认情况下,列是nullable:false
  • update: boolean - 指示"save"操作是否更新列值。如果为false,则只能在第一次插入对象时编写该值。
    默认值为"true"。
  • select: boolean - 定义在进行查询时是否默认隐藏此列。 设置为false时,列数据不会显示标准查询。 默认情况下,列是select:true
  • default: string - 添加数据库级列的DEFAULT值。
  • primary: boolean - 将列标记为主要列。 使用方式和@ PrimaryColumn相同。
  • unique: boolean - 将列标记为唯一列(创建唯一约束)。
  • comment: string - 数据库列备注,并非所有数据库类型都支持。
  • precision: number - 十进制(精确数字)列的精度(仅适用于十进制列),这是为值存储的最大位数。仅用于某些列类型。
  • scale: number - 十进制(精确数字)列的比例(仅适用于十进制列),表示小数点右侧的位数,且不得大于精度。 仅用于某些列类型。
  • zerofill: boolean - 将ZEROFILL属性设置为数字列。 仅在 MySQL 中使用。 如果是true,MySQL 会自动将UNSIGNED属性添加到此列。
  • unsigned: boolean - 将UNSIGNED属性设置为数字列。 仅在 MySQL 中使用。
  • charset: string - 定义列字符集。 并非所有数据库类型都支持。
  • collation: string - 定义列排序规则。
  • enum: string[]|AnyEnum - 在enum列类型中使用,以指定允许的枚举值列表。 你也可以指定数组或指定枚举类。
  • asExpression: string - 生成的列表达式。 仅在MySQL中使用。
  • generatedType: "VIRTUAL"|"STORED" - 生成的列类型。 仅在MySQL中使用。
  • hstoreType: "object"|"string" -返回HSTORE列类型。 以字符串或对象的形式返回值。 仅在Postgres中使用。
  • array: boolean - 用于可以是数组的 postgres 列类型(例如 int [])
  • transformer: { from(value: DatabaseType): EntityType, to(value: EntityType): DatabaseType } - 用于将任意类型EntityType的属性编组为数据库支持的类型DatabaseType

注意:大多数列选项都是特定于 RDBMS 的,并且在MongoDB中不可用。

实体继承

你可以使用实体继承减少代码中的重复。

例如,你有Photo, Question, Post 三个实体:

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

    @Column()
    title: string;

    @Column()
    description: string;

    @Column()
    size: string;
}

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

    @Column()
    title: string;

    @Column()
    description: string;

    @Column()
    answersCount: number;
}

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

    @Column()
    title: string;

    @Column()
    description: string;

    @Column()
    viewCount: number;
}

正如你所看到的,所有这些实体都有共同的列:idtitledescription。 为了减少重复并产生更好的抽象,我们可以为它们创建一个名为Content的基类:

export abstract class Content {
    @PrimaryGeneratedColumn()
    id: number;

    @Column()
    title: string;

    @Column()
    description: string;
}
@Entity()
export class Photo extends Content {
    @Column()
    size: string;
}

@Entity()
export class Question extends Content {
    @Column()
    answersCount: number;
}

@Entity()
export class Post extends Content {
    @Column()
    viewCount: number;
}

来自父实体的所有列(relations,embeds 等)(父级也可以扩展其他实体)将在最终实体中继承和创建。

树实体

TypeORM 支持存储树结构的 Adjacency 列表和 Closure 表模式。

邻接列表

邻接列表是一个具有自引用的简单模型。
这种方法的好处是简单,缺点是你不能因为连接限制而立刻加载一个树实体。

例如:

import { Entity, Column, PrimaryGeneratedColumn, ManyToOne, OneToMany } from "typeorm";

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

    @Column()
    name: string;

    @Column()
    description: string;

    @OneToMany(type => Category, category => category.children)
    parent: Category;

    @ManyToOne(type => Category, category => category.parent)
    children: Category;
}

Closure 表

closure 表以特殊方式在单独的表中存储父和子之间的关系。
它在读写方面都很有效。

要了解有关 closure 表的更多信息,请查看 this awesome presentation by Bill Karwin.

例如:

import { Entity, Tree, Column, PrimaryGeneratedColumn, TreeChildren, TreeParent, TreeLevelColumn } from "typeorm";

@Entity()
@Tree("closure-table")
export class Category {
    @PrimaryGeneratedColumn()
    id: number;

    @Column()
    name: string;

    @Column()
    description: string;

    @TreeChildren()
    children: Category;

    @TreeParent()
    parent: Category;

    @TreeLevelColumn()
    level: number;
}