TypeORM
本文档从 v3.4.0 版本起废弃。
TypeORM 是 node.js
现有社区最成熟的对象关系映射器(ORM
)。Midway 和 TypeORM 搭配,使开发更简单。
相关信息:
描述 | |
---|---|
可用于标准项目 | ✅ |
可用于 Serverless | ✅ |
可用于一体化 | ✅ |
安装组件
安装 orm 组件,提供数据库 ORM 能力。
$ npm i @midwayjs/orm@3 typeorm --save
或者在 package.json
中增加如下依赖后,重新安装。
{
"dependencies": {
"@midwayjs/orm": "^3.0.0",
"typeorm": "~0.3.0",
// ...
},
"devDependencies": {
// ...
}
}
引入组件
在 src/configuration.ts
引入 orm 组件,示例如下。
// configuration.ts
import { Configuration } from '@midwayjs/core';
import * as orm from '@midwayjs/orm';
import { join } from 'path';
@Configuration({
imports: [
// ...
orm // 加载 orm 组件
],
importConfigs: [
join(__dirname, './config')
]
})
export class ContainerConfiguratin {
}
安装数据库 Driver
常用数据库驱动如下,选择你对应连接的数据库类型安装:
# for MySQL or MariaDB,也可以使用 mysql2 替代
npm install mysql --save
npm install mysql2 --save
# for PostgreSQL or CockroachDB
npm install pg --save
# for SQLite
npm install sqlite3 --save
# for Microsoft SQL Server
npm install mssql --save
# for sql.js
npm install sql.js --save
# for Oracle
npm install oracledb --save
# for MongoDB(experimental)
npm install mongodb --save
To make the** Oracle driver work**, you need to follow the installation instructions from their site.
简单的目录结构
我们以一个简单的项目举例,其他结构请自行参考。
MyProject
├── src // TS 根目录
│ ├── config
│ │ └── config.default.ts // 应用配置文件
│ ├── entity // 实体(数据库 Model) 目录
│ │ └── photo.ts // 实体文件
│ │ └── photoMetadata.ts
│ ├── configuration.ts // Midway 配置文件
│ └── service // 其他的服务目录
├── .gitignore
├── package.json
├── README.md
└── tsconfig.json
在这里,我们的数据库实体主要放在 entity
目录(非强制),这只是一个简单的约定。
入门
下面,我们将以 mysql 举例。
1、创建 Model
我们通过模型和数据库关联,在应用中的模型就是数据库表,在 TypeORM 中,模型是和实体绑定的,每一个实体(Entity) 文件,即是 Model,也是实体(Entity)。
在示例中,需要一个实体,我们这里拿 photo
举例。新建 entity 目录,在其中添加实体文件 photo.ts
,一个简单的实体如下。
// entity/photo.ts
export class Photo {
id: number;
name: string;
description: string;
filename: string;
views: number;
isPublished: boolean;
}
要注意,这里的实体文件的每一个属性,其实是和数据库表一一对应的,基于现有的数据库表,我们往上添加内容。
2、添加实体模型装饰器
我们使用 EntityModel
来定义一个实体模型类。
// entity/photo.ts
import { EntityModel } from '@midwayjs/orm';
@EntityModel('photo')
export class Photo {
id: number;
name: string;
description: string;
filename: string;
views: number;
isPublished: boolean;
}
注意,这里的 EntityModel 是 midway 做了封装的特殊装饰器,为了和 midway 更好的结合使用。请不要直接使用 typeorm 中的 Entity。
如果表名和当前的实体名不同,可以在参数中指定。
// entity/photo.ts
import { EntityModel } from '@midwayjs/orm';
@EntityModel('photo_table_name')
export class Photo {
id: number;
name: string;
description: string;
filename: string;
views: number;
isPublished: boolean;
}
这些实体列也可以使用 typeorm_generator 工具生成。
3、添加数据库列
通过 typeorm 提供的 @Column
装饰器来修饰属性,每一个属性对应一个列。
// entity/photo.ts
import { EntityModel } from '@midwayjs/orm';
import { Column } from 'typeorm';
@EntityModel()
export class Photo {
@Column()
id: number;
@Column()
name: string;
@Column()
description: string;
@Column()
filename: string;
@Column()
views: number;
@Column()
isPublished: boolean;
}
现在 id
, name
, description
,filename
, views
, isPublished
列将添加到 photo
表中。数据库中的列类型是根据您使用的属性类型推断出来的,例如 number 将转换为整数,将字符串转换为 varchar,将布尔值转换为 bool,等等。但是您可以通过在 @Column
装饰器中显式指定列类型来使用数据库支持的任何列类型。
我们生成了带有列的数据库表,但是还剩下一件事。每个数据库表必须具有带主键的列。
数据库列包括更多的列选项(ColumnOptions),比如修改列名,指定列类型,列长度等,更多的选项请参考 官方文档。
4、创建主键列
每个实体必须至少具有一个主键列。要使列成为主键,您需要使用 @PrimaryColumn
装饰器。
// entity/photo.ts
import { EntityModel } from '@midwayjs/orm';
import { Column, PrimaryColumn } from 'typeorm';
@EntityModel()
export class Photo {
@PrimaryColumn()
id: number;
@Column()
name: string;
@Column()
description: string;
@Column()
filename: string;
@Column()
views: number;
@Column()
isPublished: boolean;
}
5、创建自增主键列
现在,如果要设置自增的 id 列,需要将 @PrimaryColumn
装饰器更改为 @PrimaryGeneratedColumn
装饰器:
// entity/photo.ts
import { EntityModel } from '@midwayjs/orm';
import { Column, PrimaryGeneratedColumn } from 'typeorm';
@EntityModel()
export class Photo {
@PrimaryGeneratedColumn()
id: number;
@Column()
name: string;
@Column()
description: string;
@Column()
filename: string;
@Column()
views: number;
@Column()
isPublished: boolean;
}
6、列数据类型
接下来,让我们调整数据类型。默认情况下,字符串映射到类似 varchar(255)
的类型(取决于数据库类型)。 Number 映射为类似整数的类型(取决于数据库类型)。但是我们不希望所有列都限制为 varchars 或整数,这个时候可以做一些修改。
// entity/photo.ts
import { EntityModel } from '@midwayjs/orm';
import { Column, PrimaryGeneratedColumn } from 'typeorm';
@EntityModel()
export class Photo {
@PrimaryGeneratedColumn()
id: number;
@Column({
length: 100
})
name: string;
@Column('text')
description: string;
@Column()
filename: string;
@Column("double")
views: number;
@Column()
isPublished: boolean;
}
示例,不同列名
@Column({
length: 100,
name: 'custom_name'
})
name: string;
此外还有有几种特殊的列类型可以使用:
@CreateDateColumn
是一个特殊列,自动为实体插入日期。@UpdateDateColumn
是一个特殊列,在每次调用实体管理器或存储库的save时,自动更新实体日期。@VersionColumn
是一个特殊列,在每次调用实体管理器或存储库的save时自动增长实体版本(增量编号)。@DeleteDateColumn
是一个特殊列,会在调用 soft-delete(软删除)时自动设置实体的删除时间。
列类型是特定于数据库的。您可以设置数据库支持的任何列类型。有关支持的列类型的更多信息,请参见此处。
CreateDateColumn
和 UpdateDateColumn
是依靠第一次同步表结构时,创建列上的默认数据完成的插入日期功能,如果是自己创建的表,需要自行在列上加入默认数据。
7、配置连接信息
请参考 配置 章节,增加配置文件。
然后在 config.default.ts
中配置数据库连接信息。
// src/config/config.default.ts
export default {
// ...
orm: {
/**
* 单数据库实例
*/
type: 'mysql',
host: '',
port: 3306,
username: '',
password: '',
database: undefined,
synchronize: false, // 如果第一次使用,不存在表,有同步的需求可以写 true
logging: false,
},
}
默认存储的是 utc 时间(推荐)。
也可以配置时区(不建议)
// src/config/config.default.ts
export default {
// ...
orm: {
// ...
timezone: '+08:00',
},
}
这个 type
字段你可以使用其他的数据库类型,包括mysql
, mariadb
, postgres
, cockroachdb
, sqlite
, mssql
, oracle
, cordova
, nativescript
, react-native
, expo
, or mongodb
比如 sqlite,则只需要以下信息。
// src/config/config.default.ts
export default {
// ...
orm: {
type: 'sqlite',
database: path.join(__dirname, '../../test.sqlite'),
synchronize: true,
logging: true,
},
}
注意:synchronize 字段用于同步表结构。使用 synchronize: true
进行生产模式同步是不安全的,在上线后,请把这个字段设置为 false。
8、使用 Model 插入数据库数据
在常见的 Midway 文件中,使用 @InjectEntityModel
装饰器注入我们配置好的 Model。我们所需要做的只是:
- 1、创建实体对象
- 2、执行
save()
import { Provide } from '@midwayjs/core';
import { InjectEntityModel } from '@midwayjs/orm';
import { Photo } from '../entity/photo';
import { Repository } from 'typeorm';
@Provide()
export class PhotoService {
@InjectEntityModel(Photo)
photoModel: Repository<Photo>;
// save
async savePhoto() {
// create a entity object
let photo = new Photo();
photo.name = 'Me and Bears';
photo.description = 'I am near polar bears';
photo.filename = 'photo-with-bears.jpg';
photo.views = 1;
photo.isPublished = true;
// save entity
const photoResult = await this.photoModel.save(photo);
// save success
console.log('photo id = ', photoResult.id);
}
}