
Midway是阿里提供的渐进式设计,提供从基础到入门再到企业级的升级方案,解决应用维护与拓展性难题
首先你需要有最新的node版本环境
使用命令行
npm init midway
根据提示即可创建完一个项目(演示为Koa为基础)
在项目中我们可以使用安装 typeorm 组件,提供数据库 ORM 能力,还需要安装数据库驱动
npm i @midwayjs/typeorm@3 typeorm --save
# for MySQL or MariaDB,Mysql8使用第二行命令
npm install mysql --save
npm install mysql2 --save
配置数据库链接
src\config\config.default.ts
import { MidwayConfig } from "@midwayjs/core";
//引入实体Model模型
如果不知道可以向下继续看
import { Photo } from "../entity/User";
export default {
// use for cookie sign key, should change to your own and keep security
keys: "1678859147957_8252",
koa: {
port: 7001
},
typeorm: {
dataSource: {
default: {
type: "mysql",
host: "118.123.238.110",
port: 3306,
username: "test1",
password: "test1",
database: "test1",
synchronize: true,
logging: true,
//配置实体模型
entities: [Photo],
// 或者扫描形式,自动配置实体模型
entities: [
'**/entity/*.entity{.ts,.js}'
]
}
}
}
} as MidwayConfig;
1、创建 Model
我们通过模型和数据库关联,在应用中的模型就是数据库表,在 TypeORM 中,模型是和实体绑定的,每一个实体(Entity) 文件,即是 Model,也是实体(Entity)。
在示例中,需要一个实体,我们这里拿 photo
举例。新建 entity 目录,在其中添加实体文件 photo.entity.ts
,一个简单的实体如下。
// entity/photo.entity.ts
export class Photo {
id: number;
name: string;
description: string;
filename: string;
views: number;
isPublished: boolean;
}
要注意,这里的实体文件的每一个属性,其实是和数据库表一一对应的,基于现有的数据库表,我们往上添加内容。
2、定义实体模型
我们使用 Entity
来定义一个实体模型类。
// entity/photo.entity.ts
import { Entity } from 'typeorm';
@Entity('photo')
export class Photo {
id: number;
name: string;
description: string;
filename: string;
views: number;
isPublished: boolean;
}
如果表名和当前的实体名不同,可以在参数中指定。
// entity/photo.entity.ts
import { Entity } from 'typeorm';
@Entity('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.entity.ts
import { Entity, Column } from 'typeorm';
@Entity()
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.entity.ts
import { Entity, Column, PrimaryColumn } from 'typeorm';
@Entity()
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.entity.ts
import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm';
@Entity()
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.entity.ts
import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm';
@Entity()
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({
type: 'timestamp',
})
createdDate: Date;
列类型是特定于数据库的。您可以设置数据库支持的任何列类型。有关支持的列类型的更多信息,请参见此处。
提示
CreateDateColumn
和 UpdateDateColumn
是依靠第一次同步表结构时,创建列上的默认数据完成的插入日期功能,如果是自己创建的表,需要自行在列上加入默认数据。
在controller文件夹下创建控制层书写业务代码
import { Inject, Controller, Post, Body } from "@midwayjs/core";
import { Context } from "@midwayjs/koa";
import { UserService } from "../service/user.service";
import { User } from "../entity/User";
// 数据通过接口传递到控制层
@Controller("/api/user")
export class APIController {
@Inject()
ctx: Context;
@Inject()
userService: UserService;
@Post("/create")
// 从Body中取出express中的body数据
async create(@Body() user: User): Promise<User> {
// 对象拷贝
Object.assign(user, {
regtime: new Date()
});
return this.userService.create(user);
}
}
来到服务层写我们的方法
import { Provide } from "@midwayjs/core";
import { IUserOptions } from "../interface";
//引入实体类
import { User } from "../entity/User";
import { Repository } from "typeorm";
import { InjectEntityModel } from "@midwayjs/typeorm";
@Provide()
export class UserService {
@InjectEntityModel(User)
// 通过实体类创建模型 userModel为模型名称
userModel: Repository<User>;
async create(user: User): Promise<User> {
//只需要保存即可将数据保存在数据库中
return this.userModel.save(user);
}
async getUser(options: IUserOptions) {
return {
uid: options.uid,
username: "mockedName",
phone: "12345678901",
email: "xxx.xxx@xxx.com"
};
}
}
还记得我们在entity中创建的实体类吗
import { Column, Entity, PrimaryColumn } from "typeorm";
// 映射表->实体类
@Entity("user")
export class User {
@PrimaryColumn({ type: "bigint" })
id: number;
@Column({ length: 100, nullable: false, unique: true })
username: string;
@Column({ length: 200, nullable: false })
password: string;
@Column({ length: 20, nullable: true })
phoneNum: string;
@Column()
regtime: Date;
}
在这里他映射了数据库中的表字段,当第一次运行时,数据库中不存在这些数据,它会自动创建表并配置信息
到此为止一个保存到数据库user表的接口就完成了,只要将在接口中通过传递json的方法把在实体类中设置的规则的参数传递,就可以完成接口的响应了
也许你可能对包装类,包装器这种名词感到陌生晦涩难懂,在下一次的文章中,将会用白话的方式帮助刚接触的朋友轻松理解