TypeORM:主列的默认值

TypeORM: Default values for primary column

尝试使用 TypeORM(在 NestJs 中)将实体保存到具有默认值的主列的数据库时遇到问题。

TL;DRdefault 似乎什么都没做时,你究竟如何使用 TypeORM 设置默认列值?

编辑 1:好的,所以 default 似乎是数据库级别,之前有点错过了,但仍然 @BeforeInsert() 应该可以解决问题(但还没有)。

编辑 2:显然 @BeforeInsert() 挂钩有效,但前提是 .save() 是用 .save(new UserSession(userId)) 而不是 .save({ userId: userId }) 调用的(这当然需要适当的构造函数UserSession).

设置

我有实体 UserSession,注意 sessionId 字段,它的默认值应该是 cryptoRandomString({ length: 128, type: 'alphanumeric' }) returns.

@Entity('user_session')
export class UserSession {
    
    @PrimaryColumn({ 
        name: 'session_id',
        default: () => cryptoRandomString({ length: 128, type: 'alphanumeric' })
    })
    sessionId: string
    
    @Column({ 
        name: 'user_id',
    })
    userId: string
   
}

然后我使用 TypeORM 存储库 .save() 函数将对象写入数据库,如下所示:

@Injectable()
export class AuthService {
    constructor(
        @InjectRepository(UserSession)
        private readonly userSessionRepository: Repository<UserSession>
    ) {}

    async createNewSession(userId: string): Promise<void> {
        // Create new session
        const session = await this.userSessionRepository.save({
            userId: userId
        })

       // If only it got that far...
    }
}

错误

在这一点上,如果没有设置 'manually',我希望 TypeORM 为 sessionId 设置一个默认值。但是,它只是抛出一个错误:

[Nest] 23088   - 04/06/2021, 23:18:44   [ExceptionsHandler] ER_NO_DEFAULT_FOR_FIELD: Field 'session_id' doesn't have a default value +4032ms
QueryFailedError: ER_NO_DEFAULT_FOR_FIELD: Field 'session_id' doesn't have a default value
    at new QueryFailedError (E:\SAC\projects\api-flexrent\node_modules\typeorm\error\QueryFailedError.js:12:28)
    at Query.<anonymous> (E:\SAC\projects\api-flexrent\node_modules\typeorm\driver\mysql\MysqlQueryRunner.js:217:45)
    at Query.<anonymous> (E:\SAC\projects\api-flexrent\node_modules\mysql\lib\Connection.js:526:10)
    at Query._callback (E:\SAC\projects\api-flexrent\node_modules\mysql\lib\Connection.js:488:16)
    at Query.Sequence.end (E:\SAC\projects\api-flexrent\node_modules\mysql\lib\protocol\sequences\Sequence.js:83:24)
    at Query.ErrorPacket (E:\SAC\projects\api-flexrent\node_modules\mysql\lib\protocol\sequences\Query.js:92:8)
    at Protocol._parsePacket (E:\SAC\projects\api-flexrent\node_modules\mysql\lib\protocol\Protocol.js:291:23)
    at Parser._parsePacket (E:\SAC\projects\api-flexrent\node_modules\mysql\lib\protocol\Parser.js:433:10)
    at Parser.write (E:\SAC\projects\api-flexrent\node_modules\mysql\lib\protocol\Parser.js:43:10)
    at Protocol.write (E:\SAC\projects\api-flexrent\node_modules\mysql\lib\protocol\Protocol.js:38:16)

绝望

在旧 google 上花了一些时间后,我尝试了几种变体,但都不起作用(并抛出相同的错误):

@PrimaryColumn({ 
    name: 'session_id',
    default: cryptoRandomString({ length: 128, type: 'alphanumeric' })
})
sessionId: string

@PrimaryColumn({ 
    name: 'session_id',
    default: () => 'cryptoRandomString({ length: 128, type: "alphanumeric" })' // Why would that even work
})
sessionId: string

@PrimaryColumn({ 
    name: 'session_id',
    default: 'cryptoRandomString({ length: 128, type: "alphanumeric" })' // Why would that even work
})
sessionId: string

@PrimaryColumn({ 
    name: 'session_id',
    default: 'please work'
})
sessionId: string

或者不在 @PrimaryColumn() 中设置 default 而是使用 @BeforeInsert(),使用 .save()

时显然不会调用它
@BeforeInsert()
beforeInsertAction(): void {
    this.sessionId = cryptoRandomString({ length: 128, type: 'alphanumeric' })
}

唯一可行的是使用 UserSession class 的构造函数并在其中设置 sessionId (我认为这有点违背 default TypeORM 中的值?):

constructor(
    userId: string
) {
    this.userId = userId
    this.sessionId = cryptoRandomString({ length: 128, type: 'alphanumeric' })
}

并用

调用它
const session = await this.userSessionRepository.save(new UserSession(userId))

所以,我错过了什么吗?首先,我是不是完全错误地处理了这件事?我不知道了。

我最终找到了解决问题的方法...

我现在这样定义我的实体 class:

@Entity('user')
export class User {

  @PrimaryColumn({ 
    name: 'user_id',
    type: 'varchar',
    length: 32
  })
  userId: string = cryptoRandomString({ length: 32, type: 'alphanumeric' })

  @Column({ 
    name: 'session_id',
    type: 'varchar',
    length: 128
  })
  sessionId: string = cryptoRandomString({ length: 128, type: 'alphanumeric' })

  @Column({ 
    name: 'email',
    type: 'varchar',
    length: 128
  })
  email: string

}

现在我可以使用存储库的 .create():

创建我的新用户实体
const user: User = this.userRepo.create({ email: 'hello.world@example.com' })

创建以下对象:

user: {
  userId: 'ivWW8oMGD8oMh2FL0vM3Grrh2FL0M3Di'
  sessionId: 'vM3DiW8oMGrh2FL0vM3DiW8oMGrh2FL0vM3DiW8oMGrh2FL0vM3DiW8oMGrh2FL0...'
  email: 'hello.world@example.com'
}

然后可以使用 .save() 方法再次保存:

await this.userRepo.save(user)