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 分钟前
Spring事务失效场景
java·后端·spring
PinkSun4 分钟前
MySQL 建表报 1030,能查不能建,排查 1 小时发现是我自己改了一行权限
后端
无相求码26 分钟前
为什么 printf 可以接受任意数量参数?变长参数的底层真相
后端
郡杰30 分钟前
Boot:MP|测验|结果封装|异常处理|前后联调|拦截器
后端
团团崽_七分甜31 分钟前
后端基础概念 - 前端开发者指南(进程、线程、事务)
后端
倔强的石头_1 小时前
从5万次到日均2000万次调用:大模型推理服务的性能工程实践V2.1
后端
环境栈笔记1 小时前
多账号浏览器选型检查清单:Profile、权限、Session 和任务日志怎么评估
前端·人工智能·后端·自动化
shepherd1112 小时前
一次把 Spring MVC 文件上传参数“查没了”的排查:multipart、Filter 与 request body 的连环坑
java·spring boot·后端
mONESY2 小时前
Node.js fs 文件系统模块 四种读写方案全解析
javascript·后端
Larcher2 小时前
从回调地狱到优雅异步:Node.js 文件操作进化史
javascript·后端·架构