TypeORM对接MongoDB时插入/保存操作忽略Column字段别名问题
问题诱因
该问题是TypeORM 0.2.x版本对接MongoDB时的已知实现缺陷:底层MongoDB驱动的写入逻辑(新增、更新)未关联实体元数据的@Column别名配置,仅查询逻辑会做数据库字段名到实体属性名的映射转换,因此写入时会直接将实体的驼峰属性名作为键写入数据库。
可行解决方案
可以根据项目实际情况选择以下任意方案解决:
方案1:升级TypeORM版本
TypeORM 0.3.x及以上正式版本已经修复了该问题,升级后@Column的name别名配置会在读写全链路生效。注意升级前需要核对版本变更日志,适配0.3.x版本调整的API(比如MongoRepository的部分调用方法、实体定义规则等),做好业务代码兼容测试。
方案2:低版本下手动加实体生命周期钩子转换
如果项目暂时无法升级TypeORM版本,可以通过实体的生命周期钩子手动做字段名转换,示例代码如下:
import { Entity, ObjectIdColumn, Column, ObjectID, BeforeInsert, BeforeUpdate, AfterLoad } from 'typeorm'; @Entity({ name: 'users' }) export class User { @ObjectIdColumn() readonly id: ObjectID; @Column({ name: "first_name" }) firstName: string; // 写入前将实体属性转为数据库别名 @BeforeInsert() @BeforeUpdate() transformToDbFields() { Object.assign(this, { first_name: this.firstName }); delete this.firstName; } // 查询后将数据库字段转为实体属性 @AfterLoad() transformToEntityFields() { this.firstName = this.first_name; delete this.first_name; } }
写入时还是正常调用原有的Repository方法即可:
const newUser = this.usersRepository.create({ firstName: 'Joe' }); return await this.usersRepository.save(newUser);
方案3:全局配置命名策略(适配全字段蛇形命名场景)
如果项目所有数据库字段都统一使用蛇形命名,不需要单独给每个字段配置name参数,可以自定义全局命名策略配合钩子实现批量转换:
- 定义命名策略类:
import { DefaultNamingStrategy, NamingStrategyInterface } from 'typeorm'; import { snakeCase } from 'typeorm/util/StringUtils'; export class SnakeCaseNamingStrategy extends DefaultNamingStrategy implements NamingStrategyInterface { columnName(propertyName: string, customName: string): string { return customName || snakeCase(propertyName); } }
- 在TypeORM配置文件中引入命名策略:
// ormconfig.ts 配置示例 module.exports = { // 其他原有配置项 namingStrategy: new SnakeCaseNamingStrategy(), }
- 配合通用的实体字段转换逻辑,或者封装通用基类让所有实体继承,减少重复代码。
内容的提问来源于stack exchange,提问作者Azerpas
相关产品推荐
相关产品推荐

