添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
跳到主要内容

实体

实体是什么?

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

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

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

@Column()
firstName: string;

@Column()
lastName: string;

@Column()
isActive: boolean;
}

这将创建以下数据库表:

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

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

每个实体都必须在连接选项中注册:

import { createConnection, Connection } from "typeorm";
import { User } from "./entity/User";

const connection: Connection = await createConnection({
type: "mysql",
host: "localhost",
port: 3306,
username: "test",
password: "test",
database: "test",
entities: [User]
});

或者你可以指定包含所有实体的整个目录, 该目录下所有实体都将被加载:

import { createConnection, Connection } from "typeorm";

const connection: Connection = await createConnection({
type: "mysql",
host: "localhost",
port: 3306,
username: "test",
password: "test",
database: "test",
entities: ["entity/*.js"]
});

如果要为 User 实体使用替代表名,可以在 @ Entity 中指定: @Entity(“my_users”) 。 如果要为应用程序中的所有数据库表设置基本前缀,可以在连接选项中指定 entityPrefix

使用实体构造函数时,其参数 必须是可选的 。 由于 ORM 在从数据库加载时才创建实体类的实例,因此在此之前并不知道构造函数的参数。

Decorators reference 中了解有关参数@Entity 的更多信息。

实体列

由于数据库表由列组成,因此实体也必须由列组成。 标有 @ Column 的每个实体类属性都将映射到数据库表列。

主列

每个实体必须至少有一个主列。 有几种类型的主要列:

  • @PrimaryColumn() 创建一个主列,它可以获取任何类型的任何值。你也可以指定列类型。 如果未指定列类型,则将从属性类型自动推断。

下面的示例将使用 int 类型创建 id,你必须在保存之前手动分配。

import { Entity, PrimaryColumn } from "typeorm";

@Entity()
export class User {
@PrimaryColumn()
id: number;
}
  • @PrimaryGeneratedColumn() 创建一个主列,该值将使用自动增量值自动生成。 它将使用 auto-increment / serial / sequence 创建 int 列(取决于数据库)。 你不必在保存之前手动分配其值,该值将会自动生成。
import { Entity, PrimaryGeneratedColumn } from "typeorm";

@Entity()
export class User {
@PrimaryGeneratedColumn()
id: number;
}
  • @PrimaryGeneratedColumn("uuid") 创建一个主列,该值将使用 uuid 自动生成。 Uuid 是一个独特的字符串 id。 你不必在保存之前手动分配其值,该值将自动生成。
import { Entity, PrimaryGeneratedColumn } from "typeorm";

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

你也可以拥有复合主列:

import { Entity, PrimaryColumn } from "typeorm";

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

@PrimaryColumn()
lastName: string;
}

当您使用 save 保存实体时,它总是先尝试使用给定的实体 ID(或 ids)在数据库中查找实体。 如果找到 id / ids,则将更新数据库中的这一行。 如果没有包含 id / ids 的行,则会插入一个新行。

要通过 id 查找实体,可以使用 manager.findOne repository.findOne 。 例:

// 使用单个主键查找一个id
const person = await connection.manager.findOne(Person, 1);
const person = await connection.getRepository(Person).findOne(1);

// 使用复合主键找到一个id
const user = await connection.manager.findOne(User, { firstName: "Timber", lastName: "Saw" });
const user = await connection.getRepository(User).findOne({ firstName: "Timber", lastName: "Saw" });

特殊列

有几种特殊的列类型可以使用:

  • @CreateDateColumn 是一个特殊列,自动为实体插入日期。无需设置此列,该值将自动设置。

  • @UpdateDateColumn 是一个特殊列,在每次调用实体管理器或存储库的 save 时,自动更新实体日期。无需设置此列,该值将自动设置。

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

空间列

MS SQL,MySQL/MariaDB 和 PostgreSQL 都支持 Spatial 列。由于各数据库列名不同,TypeORM 对数据库的支持略有差异。

MS SQL 和 MySQL/MariaDB 的 TypeORM 支持 well-known text(WKT) 的 geometries,因此 geometry 列 应该是用 string 类型标记。

TypeORM 的 PostgreSQL 支持使用 GeoJSON 作为交换格式,因此 geometry 列应在导入后标记为 object Geometry (或子类,例如 Point )。

TypeORM尝试做正确的事情,但并不总是能够确定何时插入的值或PostGIS函数的结果应被视为几何。 因此,你可能会发现自己编写的代码类似于以下代码,其中值从GeoJSON转换为PostGIS geometry ,并作为 json 转换为GeoJSON:

const origin = {
type: "Point",
coordinates: [0, 0]
};

await getManager()
.createQueryBuilder(Thing, "thing")
// 将字符串化的GeoJSON转换为具有与表规范匹配的SRID的geometry
.where("ST_Distance(geom, ST_SetSRID(ST_GeomFromGeoJSON(:origin), ST_SRID(geom))) > 0")
.orderBy({
"ST_Distance(geom, ST_SetSRID(ST_GeomFromGeoJSON(:origin), ST_SRID(geom)))": {
order: "ASC"
}
})
.setParameters({
// 字符串化 GeoJSON
origin: JSON.stringify(origin)
})
.getMany();

await getManager()
.createQueryBuilder(Thing, "thing")
// 将geometry结果转换为GeoJSON,以将此视为JSON(以便TypeORM知道反序列化它)
.select("ST_AsGeoJSON(ST_Buffer(geom, 0.1))::json geom")
.from("thing")
.getMany();

列类型

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

postgres 的列类型

int , int2 , int4 , int8 , smallint , integer , bigint , decimal , numeric , real , float , float4 , float8 , double precision , money , character varying , varchar , character , char , text , citext , hstore , bytea , bit , varbit , bit varying , timetz , timestamptz , timestamp , timestamp without time zone , timestamp with time zone , date , time , time without time zone , time with time zone , interval , bool , boolean , enum , point , line , lseg , box , path , polygon , circle , cidr , inet , macaddr , tsvector , tsquery , uuid , xml , json , jsonb , int4range , int8range , numrange , tsrange , tstzrange , daterange , geometry , geography

sqlite / cordova / react-native / expo 的列类型

int , int2 , int8 , integer , tinyint , smallint , mediumint , bigint , decimal , numeric , float , double , real , double precision , datetime , varying character , character , native character , varchar , nchar , nvarchar2 , unsigned big int , boolean , blob , text , clob , date

mssql 的列类型

int , bigint , bit , decimal , money , numeric , smallint , smallmoney , tinyint , float , real , date , datetime2 , datetime , datetimeoffset , smalldatetime , time , char , varchar , text , nchar , nvarchar , ntext , binary , image , varbinary , hierarchyid , sql_variant , timestamp , uniqueidentifier , xml , geometry , geography , rowversion

oracle 的列类型

char , nchar , nvarchar2 , varchar2 , long , raw , long raw , number , numeric , float , dec , decimal , integer , int , smallint , real , double precision , date , timestamp , timestamp with time zone , timestamp with local time zone , interval year to month , interval day to second , bfile , blob , clob , nclob , rowid , urowid

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 - 在数据库中使列 NULL NOT 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;
}

正如你所看到的,所有这些实体都有共同的列: id title description 。 为了减少重复并产生更好的抽象,我们可以为它们创建一个名为 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;
}