实体(Entities)
什么是实体?
实体是映射到数据库表(或在使用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 { DataSource } from "typeorm"
import { User } from "./entity/User"
const myDataSource = new DataSource({
type: "mysql",
host: "localhost",
port: 3306,
username: "test",
password: "test",
database: "test",
entities: [User],
})
或者您可以指定包含所有实体的整个目录 - 所有实体都将被加载:
import { DataSource } from "typeorm"
const dataSource = new DataSource({
type: "mysql",
host: "localhost",
port: 3306,
username: "test",
password: "test",
database: "test",
entities: ["entity/*.js"],
})
如果要为
User
实体设置替代表名,可以在
@Entity
中指定:
@Entity("my_users")
。
如果要为应用程序中的所有数据库表设置基本前缀,可以在数据源选项中指定
entityPrefix
。
在使用实体构造函数时,其参数**必须是可选的。由于ORM在从数据库加载时创建实体类的实例,因此不知道您的构造函数参数。
有关参数
@Entity
的详细信息,请参阅
装饰器参考
。
实体列
由于数据库表由列组成,因此您的实体也必须由列组成。
您使用
@Column
标记的每个实体类属性都将映射到数据库表列。
主键列
每个实体必须至少有一个主键列。
有几种类型的主键列:
-
@PrimaryColumn()
创建一个主键列,可以接受任何类型的值。您可以指定列类型。如果不指定列类型,它将从属性类型推断出来。下面的示例将创建一个带有
int
类型的id,您在保存之前必须手动分配其值。
import { Entity, PrimaryColumn } from "typeorm"
@Entity()
export class User {
@PrimaryColumn()
id: number
}
-
@PrimaryGeneratedColumn()
创建一个主键列,其值将自动生成具有自增值的列。它将创建一个带有
auto-increment
/
serial
/
sequence
/
identity
(取决于数据库和提供的配置)的
int
列。在保存之前,您不必手动分配其值-值将自动生成。
import { Entity, PrimaryGeneratedColumn } from "typeorm"
@Entity()
export class User {
@PrimaryGeneratedColumn()
id: number
}
-
@PrimaryGeneratedColumn("uuid")
创建一个主键列,其值将自动生成具有
uuid
的值。Uuid是一个唯一的字符串标识。在保存之前,您不必手动分配其值-值将自动生成。
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.findOneBy
或
repository.findOneBy
。示例:
const person = await dataSource.manager.findOneBy(Person, { id: 1 })
const
person = await dataSource.getRepository(Person).findOneBy({ id: 1 })
const user = await dataSource.manager.findOneBy(User, {
firstName: "Timber",
lastName: "Saw",
})
const user = await dataSource.getRepository(User).findOneBy({
firstName: "Timber",
lastName: "Saw",
})
特殊列
有几种带有附加功能的特殊列类型:
-
@CreateDateColumn
是一个特殊列,它会自动设置为实体的插入日期。
您不需要设置该列-它将自动设置。
-
@UpdateDateColumn
是一个特殊列,每次调用实体管理器或存储库的
save
时,它都会自动设置为实体的更新时间。
您不需要设置该列-它将自动设置。
-
@DeleteDateColumn
是一个特殊列,每次调用实体管理器或存储库的软删除时,它都会自动设置为实体的删除时间。
您不需要设置该列-它将自动设置。如果设置了@DeleteDateColumn,则默认范围将是“非删除”。
-
@VersionColumn
是一个特殊列,每次调用实体管理器或存储库的
save
时,它都会自动设置为实体的版本(递增数)。
您不需要设置该列-它将自动设置。
空间列
MS SQL、MySQL、MariaDB、PostgreSQL 和 CockroachDB 都支持空间列。TypeORM 对每个数据库的支持略有不同,特别是由于列名在不同数据库之间有所变化。
MS SQL 和 MySQL / MariaDB 的 TypeORM 支持将几何图形以
well-known text (WKT)
的形式提供和接受,因此几何列应该标记为
string
类型。
import { Entity, PrimaryColumn, Column } from "typeorm"
@Entity()
export class Thing {
@PrimaryColumn()
id: number
@Column("point")
point: string
@Column("linestring")
linestring: string
}
...
const thing = new Thing()
thing.point = "POINT(1 1)"
thing.linestring = "LINESTRING(0 0,1 1,2 2)"
TypeORM 的 PostgreSQL 和 CockroachDB 支持使用
GeoJSON
作为交换格式,因此几何列应该标记为
object
或
Geometry
(或其子类,如
Point
),在导入
geojson
类型
后或使用 TypeORM 内置的
GeoJSON 类型
。
import {
Entity,
PrimaryColumn,
Column,
Point,
LineString,
MultiPoint
} from "typeorm"
@Entity()
export class Thing {
@PrimaryColumn()
id: number
@Column("geometry")
point: Point
@Column("geometry")
linestring: LineString
@Column("geometry", {
spatialFeatureType: "MultiPoint",
srid: 4326,
})
multiPointWithSRID: MultiPoint
}
...
const thing = new Thing()
thing.point = {
type: "Point",
coordinates: [116.443987, 39.920843],
}
thing.linestring = {
type("LineString",
coordinates: [
[-87.623177, 41.881832],
[-90.199402, 38.627003],
[-82.446732, 38.413651],
[-87.623177, 41.881832],
],
}
thing.multiPointWithSRID = {
type: "MultiPoint",
coordinates: [
[100.0, 0.0],
[101.0, 1.0],
],
}
TypeORM试图尽力处理,但有时无法确定插入的值或PostGIS函数的结果应如何处理为几何值。因此,您可能会编写类似以下代码的代码,其中值从GeoJSON转换为PostGIS的
geometry
,并从
json
转换为GeoJSON:
import { Point } from "typeorm"
const origin: Point = {
type: "Point",
coordinates: [0, 0],
}
await dataSource.manager
.createQueryBuilder(Thing, "thing")
.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({
origin: JSON.stringify(origin),
})
.getMany()
await dataSource.manager
.createQueryBuilder(Thing, "thing")
.select("ST_AsGeoJSON(ST_Buffer(geom, 0.1))::json geom")
.from("thing")
.getMany()
列类型
TypeORM支持大多数常用的数据库支持的列类型。列类型是特定于数据库类型的,这提供了更大的灵活性,使您的数据库模式看起来更加多样化。
您可以将列类型指定为
@Column
的第一个参数,或在
@Column
的列选项中指定,例如:
或者
如果要指定其他类型参数,可以通过列选项来实现。例如:
@Column("varchar", { length: 200 })
或者
@Column({ type: "int", width: 200 })
关于
bigint
类型的注意事项:在SQL数据库中使用的
bigint
列类型不适合常规的
number
类型,而是将属性映射为
string
。
mysql
/
mariadb
的列类型
bit
、
int
、
integer
、
tinyint
、
smallint
、
mediumint
、
bigint
、
float
、
double
、
double precision
、
dec
、
decimal
、
numeric
、
fixed
、
bool
、
boolean
、
date
、
datetime
、
timestamp
、
time
、
year
、
char
、
nchar
、
national char
、
varchar
、
nvarchar
、
national varchar
、
text
、
tinytext
、
mediumtext
、
blob
、
longtext
、
tinyblob
、
mediumblob
、
longblob
、
enum
、
set
、
json
、
binary
、
varbinary
、
geometry
、
point
、
linestring
、
polygon
、
multipoint
、
multilinestring
、
multipolygon
、
geometrycollection
、
uuid
、
inet4
、
inet6
注意:UUID、INET4和INET6仅适用于mariadb以及使它们可用的相应版本。
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
、
cube
、
ltree
cockroachdb
的列类型
array
、
bool
、
boolean
、
bytes
、
bytea
、
blob
、
date
、
numeric
、
decimal
、
dec
、
float
、
float4
、
float8
、
double precision
、
real
、
inet
、
int
、
integer
、
int2
、
int8
、
int64
、
smallint
、
bigint
、
interval
、
string
、
character varying
、
character
、
char
、
char varying
、
varchar
、
text
、
time
、
time without time zone
、
timestamp
、
timestamptz
、
timestamp without time zone
、
timestamp with time zone
、
json
、
jsonb
、
uuid
注意:CockroachDB将所有数值数据类型都返回为
string
。但是,如果您省略列类型并将属性定义为
number
,ORM将把字符串解析为数字。
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
spanner
的列类型
bool
、
int64
、
float64
、
numeric
、
string
、
json
、
bytes
、
date
、
timestamp
、
array
enum
列类型
enum
列类型由
postgres
和
mysql
支持。有多种可能的列定义方式:
使用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
}
set
列类型
set
列类型由
mariadb
和
mysql
支持。有多种可能的列定义方式:
使用TypeScript的枚举:
export enum UserRole {
ADMIN = "admin",
EDITOR = "editor",
GHOST = "ghost",
}
@Entity()
export class User {
@PrimaryGeneratedColumn()
id: number
@Column({
type: "set",
enum: UserRole,
default: [UserRole.GHOST, UserRole.EDITOR],
})
roles: UserRole[]
}
使用包含
set
值的数组:
export type UserRoleType = "admin" | "editor" | "ghost",
@Entity()
export class User {
@PrimaryGeneratedColumn()
id: number;
@Column({
type: "set",
enum: ["admin", "editor", "ghost"],
default: ["ghost", "editor"]
})
roles: 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
的形式存储在单个数据库列中。当您从数据库加载数据时,姓名将作为姓名数组返回,就像您存储它们一样。
请注意,您在写入的值中
不能
有任何逗号。
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获得您的对象/数组/基本值。
生成值的列
您可以使用
@Generated
装饰器创建具有生成值的列。例如:
@Entity()
export class User {
@PrimaryColumn()
id: number
@Column()
@Generated("uuid")
uuid: string
}
uuid
值将自动生成并存储到数据库中。
除了"uuid"之外,还有"increment"、"identity"(仅适用于Postgres 10+)和"rowid"(仅适用于CockroachDB)生成类型,但某些数据库平台对于这种类型的生成有一些限制(例如,某些数据库只能有一个增量列,或者某些数据库要求增量是主键)。
列选项
列选项为实体列定义了附加选项。您可以在
@Column
中指定列选项:
@Column({
type: "varchar",
length: 150,
unique: true,
})
name: string;
ColumnOptions
中可用的选项列表:
-
type: ColumnType
- 列类型。可以是上述列类型之一。
-
name: string
- 数据库表中的列名称。默认情况下,列名称是根据属性的名称生成的。您可以通过指定自己的名称来更改它。
-
length: number
- 列类型的长度。例如,如果要创建
varchar(150)
类型,可以指定列类型和长度选项。
-
width: number
- 列类型的显示宽度。仅用于
MySQL整数类型
。
-
onUpdate: string
-
ON UPDATE
触发器。仅在
MySQL
中使用。
-
nullable: boolean
- 在数据库中将列设置为
NULL
或
NOT NULL
。默认情况下,列是
nullable: false
。
-
update: boolean
- 指示列值是否通过“save”操作进行更新。如果为false,您只能在首次插入对象时写入此值。默认值为
true
。
-
insert: boolean
- 指示列值是否在插入对象时设置。默认值为
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
列类型中用于指定允许的枚举值列表。可以指定值数组或指定枚举类。
-
enumName: string
- 定义所使用枚举的名称。
-
asExpression: string
- 生成的列表达式。仅在
MySQL
中使用。
-
generatedType: "VIRTUAL"|"STORED"
- 生成的列类型。仅在
MySQL
中使用。
-
hstoreType: "object"|"string"
-
HSTORE
列的返回类型。将值返回为字符串或对象。仅在
Postgres
中使用。
-
array: boolean
- 用于可以是数组的postgres和cockroachdb列类型(例如int[])。
-
transformer: { from(value: DatabaseType): EntityType, to(value: EntityType): DatabaseType }
- 用于将任意类型
EntityType
的属性转换为数据库支持的类型
DatabaseType
。也支持数组的转换器,写入时将按照自然顺序应用,并在读取时以相反顺序应用。例如
[lowercase, encrypt]
将在写入时先将字符串转换为小写,然后加密,而在读取时解密然后不进行任何操作。
注意:这些列选项大多是特定于关系数据库管理系统(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
}
所有来自父实体的列(关系、嵌入等)(父实体也可以扩展其他实体)都将被继承并创建在最终实体中。
树状实体
TypeORM支持使用邻接列表和闭包表模式存储树结构。
邻接列表
邻接列表是一种具有自引用关系的简单模型。
这种方法的好处是简单性,缺点是由于联接限制,无法一次加载大型树结构。
示例:
import {
Entity,
Column,
PrimaryGeneratedColumn,
ManyToOne,
OneToMany,
} from "typeorm"
@Entity()
export class Category {
@PrimaryGeneratedColumn()
id: number
@Column()
name: string
@Column()
description: string
@ManyToOne((type) => Category, (category) => category.children)
parent: Category
@OneToMany((type) => Category, (category) => category.parent)
children: Category[]
}
闭包表
闭包表在一个单独的表中以特殊的方式存储父子关系。
它在读取和写入时都非常高效。