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 小时前
什么是OpenSSL
后端·安全·程序员
bobz9653 小时前
mcp 直接操作浏览器
后端
前端小张同学6 小时前
服务器部署 gitlab 占用空间太大怎么办,优化思路。
后端
databook6 小时前
Manim实现闪光轨迹特效
后端·python·动效
武子康7 小时前
大数据-98 Spark 从 DStream 到 Structured Streaming:Spark 实时计算的演进
大数据·后端·spark
该用户已不存在7 小时前
6个值得收藏的.NET ORM 框架
前端·后端·.net
文心快码BaiduComate7 小时前
文心快码入选2025服贸会“数智影响力”先锋案例
前端·后端·程序员
neoooo7 小时前
🌐 Cloudflare Tunnel vs ZeroTier:两个世界的内网穿透哲学
后端
涡能增压发动积7 小时前
当你不了解“异步”时请慎用“异步”——记一次生产环境故障排查之旅
后端
文心快码BaiduComate7 小时前
用Comate Zulu开发一款微信小程序
前端·后端·微信小程序