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. 上述都是单数据库操作的配置操作,如果是多数据库操作的话,则需要做相关的调整。具体参考官网多数据库支持。
相关推荐
子兮曰3 天前
jev-ultrafast 深度解析:7 秒订机票的浏览器 Agent 是如何炼成的
前端·后端·agent
子兮曰3 天前
Jev 爆发一周:7 秒 Agent 背后的 System One 生态与三场争议
前端·后端·ai编程
爱勇宝3 天前
ZCode 开源 24 小时:一份没有历史的账本,回答不了"有没有偷代码"
前端·后端·chatglm (智谱)
胡写代码3 天前
别再前后端各写一套表单校验了
java·后端
大勇前进3 天前
原生 PHP 还是 Laravel?小项目到底要不要上框架
后端
yuzhi_liu3 天前
我用 LangGraph4j 实现 Multi-Agent Supervisor
后端
alsmile3 天前
Node-RED 之外,国产规则引擎的新方案:基于标准语法,Go 先行实现
后端·开源·go
大白803 天前
PHP 内存溢出排查思路:看懂报错日志,精准定位问题
后端
二月龙3 天前
PHP 接口返回统一响应封装,让前后端对接更省心
后端
盖伦发发3 天前
软件工程SOLID 五大设计原则
后端·软件工程