Midwayjs 之 编写typeorm的事务配置和查询过滤

介绍

官网文档TypeORM把基本的操作都进行了描述。但是关于复杂条件的查询和事务相关的内容,不太适合实际的项目使用,所以编写这篇文章来说明这些内容。

这是Midwayjs系列的第四篇,其他三篇:
Midwayjs 之 配置mysql数据库并自动生成entity
Midwayjs 之 编写baseEntity和baseService以及思考
Midwayjs 之 编写baseController和配置swagger

查询操作

过滤

这里描述的查询条件,都是基于单表操作的。如果涉及多表操作,则可以直接编写SQL文件,或者根据官网QueryBuilder来进行扩展。

  1. 官网TypeORM提供了一个操作符枚举:

可以如下使用:

js 复制代码
  async queryAllByCode(codes: string[]) {
    const where = {
      ref_serve_code: In(codes),
    };
    return await super.list(where);
  }
  1. 也可以这样使用:
js 复制代码
  async page(data: SystemQueryModel) {
    const { name = '' } = data;
    const where = {};

    if (data.queryType === QueryType.MANAGER) {
      where['manager_users'] = `Like(%,${data.operator_id},%)`;
    } else if (data.queryType === QueryType.DEVELOPER) {
      where['developer_users'] = `Like(%,${data.operator_id},%)`;
    }

    if (name) {
      where['name'] = `Like(%${data.name}%)`;
    }

    return await super.pageBuilder(data, where);
  }

直接SQL

js 复制代码
  async deleteDate(ids: string[]) {
    return await this.tm
      .db()
      .query('DELETE FROM serve_controller_method WHERE id IN (?)', [ids]);
  }

分页

分页查询的,一般都需要分装基类方法,直接上代码:

js 复制代码
  async pageBuilder(data, where = {}) {
    const { _value } = data;

    const newWhere: any = {};
    Object.keys(where).forEach(element => {
      if (where[element]) newWhere[element] = And(where[element]);
    });

    const [list, total] = await this.entity.findAndCount({
      where: newWhere,
      take: _value.pageSize,
      skip: (_value.current - 1) * _value.pageSize,
    });
    return {
      list,
      pagination: { total, size: _value.pageSize, page: _value.current },
    };
  }

事务

进行事务操作时,需要使用TypeORMDataSourceManager对象,在transaction方法中进行操作。封装事务的基本如下:

js 复制代码
import { Inject, Provide } from '@midwayjs/core';
import { EntityManager } from 'typeorm';
import { TypeORMDataSourceManager } from '@midwayjs/typeorm';
import { Context } from '@midwayjs/koa';

@Provide()
export class TransactionManager {
  @Inject()
  dataSourceManager: TypeORMDataSourceManager;

  @Inject()
  ctx: Context;

  async inTx(func) {
    const dataSource = this.dataSourceManager.getDataSource('default');
    return await dataSource.transaction(async transactionalEntityManager => {
      this.ctx.entityManager = transactionalEntityManager;
      await func();
    });
  }

  db(): EntityManager {
    if (this.ctx.entityManager) {
      return this.ctx.entityManager;
    }
    const dataSource = this.dataSourceManager.getDataSource('default');
    return dataSource.manager;
  }
}

使用样例

多个删除、修改、新增操作,样例代码如下:

js 复制代码
@Provide()
export class ServeService extends BaseService<ServeRegister> {
  @Inject()  // 必须在这里引入事务基类
  tm: TransactionManager;

  async deleteDate(ids: string[]) {
    // 包住 复杂操作
    return await this.tm.inTx(async () => {
      // 查询所有服务
      const allServe = await this.queryAll(ids);
      const allServeCode: string[] = [];
      // TODO  获取数据操作
      const allControllerId: string[] = [];
      // TODO  获取数据操作
      const allMethodId: string[] = [];
      // TODO  获取数据操作

      // 删除所有服务、控制器、方法
      if (allMethodId.length > 0)
        await this.methodService.deleteDate(allMethodId);
      if (allControllerId.length > 0)
        await this.serveController.deleteDate(allControllerId);

      return await this.tm.db().delete(ServeRegister, ids);
    });
  }
}

具体操作的服务,样例代码如下:

js 复制代码
@Provide()
export class ServeControllerMethodService extends BaseService<ServeControllerMethod> {
  @Inject()  // 必须在这里引入事务基类
  tm: TransactionManager;

  async deleteDate(ids: string[]) {
    return await this.tm.db().delete(ServeControllerMethod, ids);
  }
}

通过上述的操作,事务回滚起效了,如果出现异常的话。

注意

  1. 这种多个异步操作,必须添加 await 标识符。不然其他异常操作里面出现异常,不会被上层捕获,导致事务无法回滚。
  2. 上述都是单数据库操作的配置操作,如果是多数据库操作的话,则需要做相关的调整。具体参考官网多数据库支持
相关推荐
m0_748235951 分钟前
SpringBoot:解决前后端请求跨域问题(详细教程)
java·spring boot·后端
坚定信念,勇往无前1 小时前
springboot单机支持1w并发,需要做哪些优化
java·spring boot·后端
后端小肥肠1 小时前
【AI编程】Java程序员如何用Cursor 3小时搞定CAS单点登录前端集成
前端·后端·cursor
老友@2 小时前
OnlyOffice:前端编辑器与后端API实现高效办公
前端·后端·websocket·编辑器·onlyoffice
祈澈菇凉2 小时前
如何优化 Webpack 的构建速度?
前端·webpack·node.js
风月歌3 小时前
基于springboot校园健康系统的设计与实现(源码+文档)
java·spring boot·后端·mysql·毕业设计·mybatis·源码
m0_748239473 小时前
Spring Boot框架知识总结(超详细)
java·spring boot·后端
m0_748236113 小时前
Spring Boot 实战:轻松实现文件上传与下载功能
linux·spring boot·后端
m0_748245923 小时前
Spring Boot(七):Swagger 接口文档
java·spring boot·后端
青灯文案14 小时前
如何在 SpringBoot 项目使用 Redis 的 Pipeline 功能
spring boot·redis·后端