typesafe TypeORM 异常错误处理

Posted

技术标签:

【中文标题】typesafe TypeORM 异常错误处理【英文标题】:typesafe TypeORM exception error handling 【发布时间】:2020-06-05 00:26:43 【问题描述】:

我想使用 MongoDB 创建一个包含 NestJs 和 TypeORM 的应用程序。假设我有一个实体,除了 ID 字段之外还有两个唯一字段

@Entity()
export class Module extends BaseEntity 
  @ObjectIdColumn()
  public id: ObjectID;

  @Column( unique: true )
  public moduleName: string;

  @Column( unique: true )
  public displayName: string;

当我想使用已经存在的 moduleNamedisplayName 创建新模块时,我收到以下异常错误

[Nest] 6624   - 2020-02-20 16:31:36   [ExceptionsHandler] E11000 duplicate key error collection: test-mongo.module index: UQ_61128bd419e3c3a6d8d7d565ed9 dup key:  moduleName: "firstModule"  +23849ms
BulkWriteError: E11000 duplicate key error collection: test-mongo.module index: UQ_61128bd419e3c3a6d8d7d565ed9 dup key:  moduleName: "firstModule" 
    at OrderedBulkOperation.handleWriteError (C:\Users\mhermsen\Gitlab Repositories\server\node_modules\mongodb\lib\bulk\common.js:1210:11)
    at resultHandler (C:\Users\mhermsen\Gitlab Repositories\server\node_modules\mongodb\lib\bulk\common.js:519:23)
    at C:\Users\mhermsen\Gitlab Repositories\server\node_modules\mongodb\lib\core\connection\pool.js:404:18
    at processTicksAndRejections (internal/process/task_queues.js:76:11)

所以在我的 catch 语句中,我必须处理传入的错误。我要做的是

try 
  // create module
 catch (error) 
  if (/* error is TypeORM error */) 
    if (/* wrong attribute is the module name */) 
      // module name exists ...
    

    if (/* wrong attribute is the display name */) 
      // display name exists ...
    
  

TypeORM 是否公开预制异常?有我可以使用的枚举吗?获取这些 TypeORM 数据库错误的好方法是什么?


这里似乎列出了一些错误

https://github.com/typeorm/typeorm/tree/master/src/error

但我无法导入它们,也没有找到关于 BulkWriteError 的任何信息


在我的 catch 语句中,可以做类似的事情

const code: number = error.code;

if (code === 11000) 
  throw new ConstraintException(error.errmsg);


throw error;

但如您所知,这不是最好的方法。此外,此错误对象不会告诉我 moduleNamedisplayName 是否无效。就在一个字符串内

errmsg: 'E11000 重复键错误集合:test-mongo.module 索引:UQ_61128bd419e3c3a6d8d7d565ed9 复制键:模块名称: "第一个模块" ',

我是否必须创建自己的从这些错误代码到异常的映射?

【问题讨论】:

您在 typeorm lib 中找不到任何有关该错误的信息,因为它是由 mongo 适配器引发的。 Here你可以找到你提到的错误。此外,您可以做的最好的事情是使用@types/mongodb,它会暴露MongoError:: code?: number。但不幸的是,该软件包没有提供带有错误列表的枚举。 感谢您的回复。那么错误代码与TypeORM无关吗?那么唯一的解决方案是在插入数据之前通过 select 进行多次检查? 是的,此类错误与 db 相关。作为一个选项,您可以验证具有相同唯一字段的记录不存在。但我会依赖带有错误处理的 mongo 功能 - 就像您使用 ConstraintException 的代码示例一样。正如你所看到的,还有一个空间可以为@types/mongodb 做出贡献 - 带有错误代码的枚举:) 问题是我有其他项目依赖于 Postgres/MSSQL,一个很好的错误处理方式会很棒:) NestJS 提供 DI 机制。您可以使用通用错误实现特定于数据库的错误处理程序,并将处理程序注入您需要的服务(例如,取决于您的应用程序配置)。 【参考方案1】:

我不确定您是否找到了答案,但这是我使用的另一种方法。这与 typeorm 数据库类型无关。

我尝试使用自定义装饰器在调用数据库服务时捕获异常(任何像这样的 crud 操作)

这是我的自定义装饰器(函数装饰器。你可以选择装饰器的类型。它也可以是类装饰器)

target: - 当前对象的原型

属性:- 方法的名称

descriptor: - 方法的属性描述符,即 Object.getOwnProperDescriptor

注意:Nestjs 的当前实现采用 swagger 的实现方式 - 如果方法的 args/return 值发生更改,它不会使用正确的响应对象呈现 Swagger API 部分。因此使用 Proxy 的概念来改变行为

export const DatabaseFailureHandler = (target: any, property: string, descriptor: PropertyDescriptor): any => 
  const className = target.constructor.name;
 // 
  const original = descriptor.value;

  let customException;
  // const proxyHandlerFn = function(target, )
  descriptor.value = new Proxy(original, 
    apply: async function(target, thisArg, args) 
      console.log(`Call with args: $args -------$className#`);
      let result;
      try 
        result = await target.apply(thisArg, args);
        console.log('result in databasefailure handling"', result);
        //WARNING!!! - Test only
        // throw new Error('DatabaseException');
        return result;
       catch (err) 
        // TODO: Replace with the actual logger with the logs of service and class names
        console.log('err capt:', err);

// Below is my custom exception implementation that has my required details. You can 
 //modify it to have the className, methodName args, etc...
        customException = new AppConfigService(new AppUtilService()).retrieveCustomHttpException(
          HttpStatus.INTERNAL_SERVER_ERROR,
          MATRIX_API.ERROR_MSG.DATABASE_ERROR + `:$err.name`,
          err,
          HttpStatus.INTERNAL_SERVER_ERROR.toString(),
          MATRIX_API.DATABASE.ERR_TYPE.DATABASE_EXCEPTION_ERR_TYPE,
          err.message
        );
        throw customException;
      
    
  );
;

现在这在我的 service.ts 中实现为像这样的自定义装饰器

@DatabaseFailureHandler
  async updateXXXXSkill(
    corpId: string,
    skillId: number,
    skillUpdate: UpdateRequestModel
  ): Promise<UpdateResponseModel> 
// Either get the repo from connection or entity manager or Inject them if TypeORMModule is used
    const entity: Employee = this.repository.create(
      ...skillUpdate,
      corpId,
      skillId
    );
    await this.repository.update(
      
        corpId,
        skillId
      ,
      entity
    );
    return XXXXX;
  

希望这种方法使您能够捕获所有错误详细信息并通过自定义异常过滤器抛出它们。这是我为捕获任何异常而编写的集中式过滤器。它在服务器启动时注册。你可以关注官方的nestjs文档

【讨论】:

以上是关于typesafe TypeORM 异常错误处理的主要内容,如果未能解决你的问题,请参考以下文章

ORACLE 异常错误处理

异常处理

异常处理

异常处理

异常处理

异常处理