在 MidwayJS 中使用 TypeORM的进行数据持久化操作

lxf2023-04-12 20:30:02

开启AdminJS成长之旅!这是我参与「AdminJS · 12 月更文挑战」的第29天,点击查看活动详情

Midway是面向未来的一款支持Serverless的Node框架,其内置的web框架也是非常的好用,还有一些其他的特性,前后端一体等等。

TypeORM是一款非常实用的 ORM框架,可以通过实体的操作来对数据库的数据进行读写,只要将实体定义出来之后就可以非常简便的操作数据库了

准备工作

Midway中对TypeORM做了定制化,首先安装依赖,这里需要安装数据库驱动和typeorm

$ npm i @midwayjs/orm typeorm --save
$ npm install mysql2 --save

然后将orm引入configuration.ts中

import { Configuration } from '@midwayjs/decorator';
import * as orm from '@midwayjs/orm';

@Configuration({
  imports: [
    orm                             // 加载 orm 组件
  ],
  // ……
})
export class ContainerConfiguratin {

}

在config.local.ts中添加数据库配置

export const orm = {
  type: 'mysql',
  host: '127.0.0.1',
  port: 3306,
  username: 'remote',
  password: '123456',
  database: 'your_db_name',
  synchronize: false,   // 如果第一次使用,不存在表,有同步的需求可以写 true
  logging: false,
};

创建实体

所谓的实体就是一个对象,这里我们使用User实体来做示例,我们第一步只需要将实体的属性罗列出来

class User {
  id: number;
  username: string;
  phone: string;
  sex: number;
  email: string;
  createTime: Date;
}

现在我们需要使用装饰器来修饰一下这个对象,让它变成框架可以是别的实体

  1. 在原生的TypeORM中,声明实体使用的是@Entity,在Midway中使用的是@EntityModel装饰器,可以更好地和Midway结合
  2. 使用@PrimaryColumn来声明主键(PrimaryGeneratedColumn可以声明自增主键);使用@Column声明普通列,可以声明列的类型(默认是varchar(255))、名称……;使用@CreateDateColumn@UpdateDateColumn可以声明创建时间个更新时间,这两个时间会自动生成,不需要我们额外去维护
@EntityModel('user') // 可以指定表名,不指定会根据类名自己生成
export class User {
  @PrimaryGeneratedColumn()
  id: number;
  
  @Column({
    length: 20, // 长度
    name: 'user_name' // 指定列名
  })
  username: string;
  
  @Column({
    nullable: true, // 是否可以为空
    length: 11
  })
  phone: string;
  
  @Column({
    default: 0, // 默认值
    length: 1
  })
  sex: number;
  
  @Column({
    length: 30,
    nullable: true,
  })
  email: string;
  
  @CreateDateColumn()
  createTime: Date;
}

这样一个可以被TypeORM识别的简单实体类就完成了

数据库操作

在进行数据库的操作之前我们需要先注入Entity的Model,通过@InjectEntityModel注解来进行操作数据库

import { Provide, Inject } from '@midwayjs/decorator';
import { InjectEntityModel } from '@midwayjs/orm';
import { User } from './entity/user';
import { Repository } from 'typeorm';

@Provide()
export class UserService {

  @InjectEntityModel(User)
  userModel: Repository<User>;
}

现在已经注入了userModel,下面的所有的数据库操作都会基于这个userModel进行

新增数据库记录只需要创建一个实体类的实例,将属性值复制之后调用userModel的insert方法即可添加数据

@Provide()
export class UserService {

  @InjectEntityModel(User)
  userModel: Repository<User>;
  
  async saveUser(): Promise<User> {
    const user = new User();
    user.username = 'King';
    
    cosnt insertRes = await this.userModel.insert(user); // save方法也可以
    return insertRes;
  }
}

如果实体中没有配置某一属性是否可以为空或者设置默认值,则必须添加一个值,否则会报错

查数据算是最复杂的一项,可以使用find和findOne等多种方法,find返回的只有一条记录,find会返回一个数组,即使只有一条记录被筛选出来。

@Provide()
export class UserService {

  @InjectEntityModel(User)
  userModel: Repository<User>;
  
  async selectUser(id: number): Promise<User> {
    cosnt user = await this.userModel.findOne({
      where: { id }
    });
    return user;
  }
  
  async selectUsers(id: number): Promise<User[]> {
    cosnt users = await this.userModel.find({
      where: { sex: 1 }
    });
    return users;
  }
}

find还有很多操作项,为了不影响整体的阅读体验,会整理一个table放在后面

删除数据很简单,只需要将要删除的数据查出来再调用一下remove方法即可

@Provide()
export class UserService {

  @InjectEntityModel(User)
  userModel: Repository<User>;
  
  async deleteUser(id: number): Promise<User> {
    cosnt user = await this.userModel.findOne({
      where: { id }
    });
    const res = await this.userModel.remove(user);
    return res;
  }
}

在开发中一般不建议将数据进行remove,更推荐的是使用标记位