NestJS中TypeORM主键列设置default默认值不生效如何解决?
问题根因
@PrimaryColumn的default配置不生效的原因default配置是数据库级属性,仅会在生成表结构时写入字段的默认值规则。你传入的cryptoRandomString是Node.js端的方法,数据库本身不存在这个函数,自然无法在插入数据时生成对应值。即便你传入固定字符串作为默认值,多数数据库的主键列也要求显式传入值,默认不会自动应用字段默认值约束。@BeforeInsert传普通对象不触发的原因
TypeORM的所有生命周期钩子(包括@BeforeInsert、@BeforeUpdate等)仅对实体类的实例生效。你直接给save()传入普通JS对象{ userId: userId }时,这个对象并不是UserSession类的实例,自然不会挂载钩子函数,也就不会触发赋值逻辑。
可行解决方案
方案1:配合repository.create()方法使用(最推荐)
create()方法会把普通对象转换为实体类的实例,自动触发生命周期钩子,你不需要修改实体原有逻辑:
async createNewSession(userId: string): Promise<void> { // 先将普通对象转为实体实例,自动触发@BeforeInsert const sessionInstance = this.userSessionRepository.create({ userId }); const session = await this.userSessionRepository.save(sessionInstance); }
这种方案完全符合TypeORM的设计规范,不需要额外写构造函数,也能保证@BeforeInsert的逻辑正常执行。
方案2:实体字段直接赋初始值
直接在实体的属性声明时赋值,只要是实体实例就会自动生成sessionId:
@Entity('user_session') export class UserSession { @PrimaryColumn({ name: 'session_id' }) sessionId: string = cryptoRandomString({ length: 128, type: 'alphanumeric' }); @Column({ name: 'user_id' }) userId: string }
调用时还是配合create()方法使用即可。
方案3:使用数据库支持的生成函数
如果你确实要走数据库层面的默认值,需要改用对应数据库支持的随机字符串函数,比如MySQL可以用UUID()搭配字符串处理函数生成符合要求的ID,不过灵活性远不如应用层生成,仅适合不需要自定义生成规则的场景:
@PrimaryColumn({ name: 'session_id', default: () => 'UUID()' // 这里写的是数据库能识别的函数 }) sessionId: string
补充说明
你之前用构造函数传new UserSession(userId)的写法本质上和create()方案是一样的,都是生成实体类实例触发赋值逻辑,只是create()是TypeORM内置的方法,不需要你手动维护构造函数,更符合框架约定。
内容的提问来源于stack exchange,提问作者Benno Grimm

