如何将 NestJS 配置注入 TypeORM 实体?

Posted

技术标签:

【中文标题】如何将 NestJS 配置注入 TypeORM 实体?【英文标题】:How to inject NestJS config into TypeORM entity? 【发布时间】:2020-06-02 20:46:25 【问题描述】:

让我们简化 TypeORM 实体User

@Entity()
export class User extends BaseDatabaseEntity 
  @Column(
    length: 255,
  )
  public firstName!: string;

  @Column( length: 60 )
  @Exclude()
  public password: string;

  @BeforeUpdate()
  @BeforeInsert()
  private hashPassword(): void 
    const tmpPassword = hashSync(
      this.password + 'config.auth.password.secret',
      genSaltSync(),
    );
    this.password = tmpPassword;
  



我需要用 NestJS 的配置(来自 ConfigService 的命名空间)替换 config.auth.password.secret

export default registerAs('app', () => 
   return 
    password: 
      secret: process.env.AUTH_PASSWORD_SECRET,
    
  ;
);

,但实体不是 NestJS 结构的一部分,所以我不能像往常一样注入它。

如何在 TypeORM 实体中实现 NestJS 配置?

【问题讨论】:

【参考方案1】:

实体不是 NestJS 中可注入提供程序的一部分,因此本质上这是不可能的。但是,您可以将其作为服务代码的一部分,并在插入/更新之前在那里进行密码散列。

【讨论】:

是的,这正是我想做的,但我不确定如何让实体成为 NestJS 的一部分。你能举个例子吗? 你不能。这就是我所说的。实体不是@Injectable(),也没有计划制作它们。相反,您应该将拥有逻辑移动到您的服务中。 This answer 更深入地解释了原因 所以我应该从实体中完全删除方法或使它们像这样:hashPassword(generator: IUserPassGenerator)? 如果您需要访问应该注入的服务,您需要在使用实体的服务中创建逻辑,或者将所需的服务注入使用实体的服务中实体并将所需的服务传递给实体的方法。就个人而言,我会选择前者而不是后者 @JayMcDoniel 但如果我需要 @Column( type: DataType.ENUM(config.get('app.i18n.languages')) ) lang: string 。如果无法使用,此配置是什么。我以前在其他框架中没有看到。【参考方案2】:

我也需要这个并想出了解决方法。如前所述,您不能将配置注入实体。

我想出了在实体中使用我需要的配置值导出对象的解决方案:

在应用模块中初始化配置:

  imports: [
    ConfigModule.forRoot(
      isGlobal: true,
      load: [defaultConfig]
    ),
// .....other imports
  ]

defaultConfig 是一个收集和检查配置值的函数。最重要的是,它将值设置为 STATIC_CONFIG 对象。

export const STATIC_CONFIG = 
  WEB_APP_URL: '',
  BASE_URL: '',
;

export const defaultConfig = () => 
  const port = +(process.env[ENV_SERVER.PORT] || 3000);
  const production = process.env.NODE_ENV === 'production';
  const retVal = 
    PRODUCTION: production,
    PORT: port,
    BASE_URL: process.env.BASE_URL || 'http://localhost:3000',
    URL_PREFIX: process.env.URL_PREFIX || 'http://localhost:3000',
//    ..... plenty of other values
  

  if (retVal[ENV_S3.HOST] && !(retVal[ENV_S3.ACCESS] && retVal[ENV_S3.SECRET])) 
    // tslint:disable-next-line:no-console
    console.error('S3 configuration error: no access or secret set; exiting');
    process.exit(1);
  

  STATIC_CONFIG.WEB_APP_URL = retVal.WEB_APP_URL;
  STATIC_CONFIG.BASE_URL = retVal.BASE_URL;

  return retVal;
;

最后在我的实体中,我使用STATIC_CONFIG 对象,例如:

  @Expose( name: 'image', toPlainOnly: true, groups: [TG_MOBILE] )
  get mobileAppImage() 
    return this.id ? `$STATIC_CONFIG.BASE_URL/static/image/$this.id` : undefined;
  

【讨论】:

【参考方案3】:
@Entity()
export class User extends BaseDatabaseEntity 
  @Column(
    length: 255,
  )
  public firstName!: string;

  @Column(
    length: 60,
    transformer: new PasswordTransformer(new ConfigService())
  )
  @Exclude()
  public password: string;

export class PasswordTransformer implements ValueTransformer 
  constructor(private config: ConfigService) 

  from(value: string): string 
    return value;
  

  to(value: string): string 
    return hashSync(
      this.password + this.config.get('AUTH_PASSWORD_SECRET'),
      genSaltSync(),
    );
  


【讨论】:

以上是关于如何将 NestJS 配置注入 TypeORM 实体?的主要内容,如果未能解决你的问题,请参考以下文章

在 Nestjs 中注入 Tree Typeorm 存储库

NestJS 基于接口注入自定义 TypeOrm 存储库

如何在 Nestjs 中使用 .env 文件设置 Typeorm 的配置

如何在 NestJs 中捕获 Typeorm 事务错误

NestJs TypeORM 异步配置

如何使用 typeorm nestjs 加入 3 个关系表