nest笔记十:typeorm使用经验小结

  • nestjs系列笔记
  • 之前的笔记:nest记笔五:使用TypeORM连接mysql,可以使用typeorm的基本功能。随着开发的深入,很多已经满足不了要求了。
  • 写这小结的时候,typeorm已经更新0.3.9了, 与之前0.2.x相比,变化蛮大的。这里的内容也是针对0.3.7及以上的版本
  • 因为我这里主要使用mysql 5.7,其它的数据库暂时没有涉及,所以这里的内容在mysql数据库,都是基本OK的。
  • 我这里的很多代码,都会使用xmcommon这个库。只需要npm i xmcommon。为什么用这个库,因为它是我自己这些积累的工具库,我使用起来很顺手。也是我的一个开源项目。

1. 使用 typeorm-model-generator 生成对已有数据库的实体类

  • typeorm可以手动改实体类,然后同步到数据库,这个功能我一直没有用。主要是担心,不小心应用到生产环境,造成数据丢失。
  • 我现在的做法是使用工具改好数据库表后,再用typeorm-model-generator生成对应typeorm需要的实体类, 再将生成好的代码文件,替换现有的。
  • typeorm-model-generator不能满足我的生成文件的要求,我fork了一个,然后发布了一个修改。参考这个文章基于typeorm的nestjs项目使用@zdhsoft/tmg将数据库生成数据模型

2. 一些特殊类型

FindOptionsWhere 是用于生成实体类where的选项,

  • 使用FindOptionsWhere的几个用处:1、typescript的语法检查,2、代码提示,提示可以有哪些做条件的字段。
  • 示例
// 一个实体类的定义
@Entity('Account')
export class Account {@Column('int', {name: 'accountType',comment: '账号类型',})public accountType: number;@Column('varchar', {name: 'accountId',comment: '用户的登陆账号',length: 200,})public accountId: string;
}// 使用实例
@Injectable()
export class AccountService {constructor(@InjectRepository(Account) private accountRepo: Repository<Account>){//}public async found(paramType: number, account: string) {// 然后就可以定义where选项了const where: FindOptionsWhere<Account> = {accountType: paramType,accountId: account,};const accountRec = await this.accountRepo.createQueryBuilder().where(where).getOne();}
}

其它类似的

  • DeepPartial 用于新增记录的时候,定义新的记录实例
  • FindOptionsSelect 一般情况下,typeorm会返回该条记录的所有字段,其实这是没有必要的。通过它,来设置我们想要的返回字段。其实还有一个FindOptionsSelectByString,但是已经标记为:deprecated
  • FindOptionsOrder 排序相关字段

3. 事物

  • 在0.3.x的版本,事物已经与0.2.x事物大不同了
import { utils, XCommonRet, getLogger } from 'xmcommon';class XTypeormUtils {/*** 事物* @param paramDS TypeORM的数据源* @param paramRunInTransaction 执行事物的函数* @param paramTransName 事物名称,没有传入空串或null*/public static async transaction<T = unknown>(paramDS: DataSource,paramRunInTransaction: (paramMgr: EntityManager) => Promise<XCommonRet<T>>,paramTransName?: string,): Promise<XCommonRet<T>> {let transTag = '';if (!utils.isEmpty(paramTransName)) {transTag = `[${paramTransName}]`;}const r = new XCommonRet<T>();const queryRunner = paramDS.createQueryRunner();log.info(`开始事物:${transTag}`);await queryRunner.startTransaction();try {// 执千事物中的逻辑const result = await paramRunInTransaction(queryRunner.manager);if (result.isNotOK) {log.warn(`事物${transTag}执行失败:${JSON.stringify(result)}`);await queryRunner.rollbackTransaction();} else {await queryRunner.commitTransaction();}r.assignFrom(result);} catch (e) {r.setError(-1, `事物异常:${String(e)}`);log.warn(`事物${transTag}异常:${JSON.stringify(r)}`);await queryRunner.rollbackTransaction();}await queryRunner.release();return r;}
}// 使用例子
// 在app.module中,imports: [TypeOrmModule.forRoot(TypeOrmConfig)后,就可以使用DataSource了
@Injectable()
export class AccountService {constructor(@InjectRepository(Account) private accountRepo: Repository<Account>, private dataSource: DataSource){//}public async found(paramType: number, account: string) {// 然后就可以定义where选项了const where: FindOptionsWhere<Account> = {accountType: paramType,accountId: account,};const accountRec = await this.accountRepo.createQueryBuilder().where(where).getOne();}// 事物使用实现public async transSample() {const result = XTypeormUtils.transaction<Account[]>(this.dataSource, (paramMgr: EntityManager) => {const r = new XCommonRet<Account[]>();do {const list = await paramMgr.createQueryBuilder(Account).getMany();r.setOk(list);} while (false);return r;});if (result.isOK) {return result.data;} else {return [];}}
}

4. 一个简化处理的工具类

import { Like, In, DataSource, EntityManager, EntityTarget, Between, MoreThanOrEqual, LessThanOrEqual } from 'typeorm';
import { utils, XCommonRet, getLogger } from 'xmcommon';
const log = getLogger(__filename);export class XTypeormUtils {/*** 简化typeorm的Like方法* @param paramValue* @returns*/public static like(paramValue?: string) {if (utils.isNull(paramValue)) {return undefined;} else {return Like(`%${paramValue}%`);}}/*** 简化typeorm的in方法* @param paramList* @returns*/public static in(paramList: unknown[]) {return In(paramList);}/*** 范围* @param paramForm 开始值* @param paramTo 结束值* @returns 返回undefined,则表示没有表达式*/public static scope<T>(paramForm?: T | null, paramTo?: T | null) {let v = 0;if (utils.isNotNull(paramForm)) {v += 1;}if (utils.isNotNull(paramTo)) {v += 2;}switch (v) {case 1:return MoreThanOrEqual<T>(paramForm as T);case 2:return LessThanOrEqual<T>(paramTo as T);case 3:return Between<T>(paramForm as T, paramTo as T);default:return undefined;}}/*** 简化typeorm的Like方法* @param paramValue* @returns*/public static like_begin(paramValue?: string) {if (utils.isNull(paramValue)) {return undefined;} else {return Like(`${paramValue}%`);}}/*** 简化typeorm的Like方法* @param paramValue* @returns*/public static like_end(paramValue?: string) {if (utils.isNull(paramValue)) {return undefined;} else {return Like(`%${paramValue}`);}}/*** 删除对象中,属性值为null或undefined的属性* @param paramWhere 要处理的对象* @returns 处理的对象*/public static cleanNull(paramWhere: any) {const delKey: string[] = [];for (const k in paramWhere) {if (utils.isNull(paramWhere[k])) {delKey.push(k);}}for (const k of delKey) {delete paramWhere[k];}return paramWhere;}/*** 处理bigint的参数* @param paramValue 要处理的值*/public static bigInt(paramValue?: number): string | undefined {if (utils.isNull(paramValue)) {return undefined;} else {return String(paramValue);}}/*** 生成查询Builder* @param paramMgr EntityManager* @param paramEntity EntityTarget<T>* @param paramAliasName 别名* @returns*/public static builder<T>(paramMgr: EntityManager,paramEntity: EntityTarget<T>,paramAliasName: string = 'a') {return paramMgr.createQueryBuilder<T>(paramEntity, paramAliasName);}/*** 事物* @param paramDS TypeORM的数据源* @param paramRunInTransaction 执行事物的函数* @param paramTransName 事物名称,没有传入空串或null*/public static async transaction<T = unknown>(paramDS: DataSource,paramRunInTransaction: (paramMgr: EntityManager) => Promise<XCommonRet<T>>,): Promise<XCommonRet<T>>;public static async transaction<T = unknown>(paramDS: DataSource,paramRunInTransaction: (paramMgr: EntityManager) => Promise<XCommonRet<T>>,paramTransName: string,): Promise<XCommonRet<T>>;public static async transaction<T = unknown>(paramDS: DataSource,paramRunInTransaction: (paramMgr: EntityManager) => Promise<XCommonRet<T>>,paramTransName?: string,): Promise<XCommonRet<T>> {let transTag = '';if (!utils.isEmpty(paramTransName)) {transTag = `[${paramTransName}]`;}const r = new XCommonRet<T>();const queryRunner = paramDS.createQueryRunner();log.info(`开始事物:${transTag}`);await queryRunner.startTransaction();try {// 执千事物中的逻辑const result = await paramRunInTransaction(queryRunner.manager);if (result.isNotOK) {log.warn(`事物${transTag}执行失败:${JSON.stringify(result)}`);await queryRunner.rollbackTransaction();} else {await queryRunner.commitTransaction();}r.assignFrom(result);} catch (e) {r.setError(-1, `事物异常:${String(e)}`);log.warn(`事物${transTag}异常:${JSON.stringify(r)}`);await queryRunner.rollbackTransaction();}await queryRunner.release();return r;}
}

5. 其它

别名

  • 很奇怪typeorm的SQL语句,都会重新命名,结查SQL事句很长,所以我这里都会使用别名, createQueryBuilder的参数可以传入别名, 一般情况下,我传入字终a

使用createQueryBuilder不能指定返回字段

  • 使用createQueryBuilder查询返回的结果,好像都会返回查询记录的所有字段,很多时间,我仅需要几个字段就可以了。 这个时候可以使用FindOptionsSelect。设置完成后,这个builder一个方法,叫setFindOptions可以用
  • 如下代码:
    const fields: FindOptionsSelect<Account> = {accountType: true};const list: Account[] = await this.repo.createQueryBuilder('a').setFindOptions({select: fields}).getMany();// 这样listt每个记录,只有一个accountType字段
  • 还有一种情况是,你不管怎么设置,都会返回一些字段,仔细观查后,发现这些字段都是主键。

打印耗时

  • typeorm初始化的时候,将logging设为true, 就可以打印出SQL语句了。但是每个SQL语句的耗时却没有,这个耗时的功能可以帮我们发现问题SQL,并优化。 其实,只要设置maxQueryExecutionTime的值就可以了,我这里将它设为1,就可以打印出来了。

最后,喜欢的话就收藏点个赞,希望对你使用有所帮助

nest笔记十:typeorm使用经验小结相关推荐

  1. kvm虚拟化学习笔记(十)之kvm虚拟机快照备份

    KVM虚拟化学习笔记系列文章列表 ---------------------------------------- kvm虚拟化学习笔记(一)之kvm虚拟化环境安装 http://koumm.blog ...

  2. Python语言入门这一篇就够了-学习笔记(十二万字)

    Python语言入门这一篇就够了-学习笔记(十二万字) 友情提示:先关注收藏,再查看,12万字保姆级 Python语言从入门到精通教程. 文章目录 Python语言入门这一篇就够了-学习笔记(十二万字 ...

  3. 机器学习笔记十四:随机森林

    在上一篇机器学习笔记十三:Ensemble思想(上)中,简要的提了一下集成学习的原理和两种主要的集成学习形式.  而在这部分要讲的随机森林,就算是其中属于bagging思路的一种学习方法.为了篇幅,b ...

  4. python中计算排队等待时间_codewars(python)练习笔记十:计算超市排队时长

    codewars(python)练习笔记十:计算超市排队时长 题目 There is a queue for the self-checkout tills at the supermarket. Y ...

  5. IOS之学习笔记十五(协议和委托的使用)

    1.协议和委托的使用 1).协议可以看下我的这篇博客 IOS之学习笔记十四(协议的定义和实现) https://blog.csdn.net/u011068702/article/details/809 ...

  6. 吴恩达《机器学习》学习笔记十四——应用机器学习的建议实现一个机器学习模型的改进

    吴恩达<机器学习>学习笔记十四--应用机器学习的建议实现一个机器学习模型的改进 一.任务介绍 二.代码实现 1.准备数据 2.代价函数 3.梯度计算 4.带有正则化的代价函数和梯度计算 5 ...

  7. 吴恩达《机器学习》学习笔记十二——机器学习系统

    吴恩达<机器学习>学习笔记十二--机器学习系统 一.设计机器学习系统的思想 1.快速实现+绘制学习曲线--寻找重点优化的方向 2.误差分析 3.数值估计 二.偏斜类问题(类别不均衡) 三. ...

  8. 吴恩达《机器学习》学习笔记十——神经网络相关(2)

    吴恩达<机器学习>学习笔记十--神经网络相关(2) 一. 代价函数 二. 反向传播算法 三. 理解反向传播算法 四. 梯度检测 五. 随机初始化 1.全部初始化为0的问题 2.随机初始化的 ...

  9. 主成分分析碎石图_ISLR读书笔记十九:主成分分析(PCA)

    本文使用 Zhihu On VSCode 创作并发布 前面写的一些统计学习方法都是属于监督学习(supervised learning),这篇主成分分析(principal components an ...

最新文章

  1. #招聘# C++高级攻城师一枚
  2. [转]C++基础:C++的结构struct
  3. Hadoop HA 双namenode搭建
  4. 深度学习之基于卷积神经网络实现超大Mnist数据集识别
  5. Android之最好理解的Binder机制
  6. 实现贝叶斯分类器_从头开始在Python中实现高斯朴素贝叶斯
  7. sqlserver调用mysql存储过程_sqlserver调用存储过程
  8. 如何查看电脑上是否安装有IIS服务
  9. 如何表达清楚一个程序:模块化设计
  10. laravel leftjoin 右侧取最新一条_高铁规划:湖南至广西将增添一条高铁,填补中西部地区铁路网空白...
  11. Andorid Studio NDK 开发 - Hello World
  12. Interface的精髓——《Thinking in Java》随笔025
  13. Android 摄像头
  14. 一次通过PMP认证考试的心得分享
  15. 掷骰子python代码_掷骰子游戏,,游戏规则:玩家投掷两个骰
  16. Eviews10 如何将季度数据转为月度数据(低频转高频)
  17. php如何取视频缩略图,视频提取缩略图
  18. matlab--找两条曲线交点并标注于图上的方法
  19. 【批量去除图片的背景】
  20. CRM系统操作权限的实现

热门文章

  1. HTTP服务器项目面试题
  2. No.4-VulnHub-Tr0ll:1-Walkthrough渗透学习
  3. 图片裁剪并上传,电脑手机均实用
  4. 如何制作patch文件?
  5. Java后端使用socketio,实现小程序答题pk功能
  6. SRE体系及稳定性建设
  7. 微信公众号php编程,PHP编程:微信公众号开发之文本消息自动回复php代码
  8. 在NUXT中播放视屏
  9. 如何显示一副超大图像
  10. 植发搞笑图片_搞笑秃头图片大全_关于秃顶的搞笑图片