【问题标题】:How to handle NestJS Dependency Injection when extending a class for a service?为服务扩展类时如何处理 NestJS 依赖注入?
【发布时间】:2019-05-15 13:21:46
【问题描述】:

我正在尝试根据我的ConfigService 中的值提供不同的服务。

我遇到的问题是,当执行findOne()(结果为null)或countDocuments()(结果为0)等查询方法时,注入的猫鼬模型不返回任何值。

我的服务类定义如下:

    export class BaseService {
      constructor(@InjectModel('Cat') public readonly catModel: Model<Cat>) {}

      createService(option: string) {
        if (option === 'OTHER') {
          return new OtherService(this.catModel);
        } else if (option === 'ANOTHER') {
          return new AnotherService(this.catModel);
        } else {
          return new BaseService(this.catModel);
        }
      }

      async findOne(id: string): Promise<Cat> {
        return await this.catModel.findOne({_id: id});
      }

      async count(): Promise<number> {
        return await this.catModel.countDocuments();
      }

      testClass() {
        console.log('BASE SERVICE CLASS USED');
      }
    }

    @Injectable()
    export class OtherService extends BaseService {
      constructor(@InjectModel('Cat') public readonly catModel: Model<Cat>) {
        super(catModel);
      }

       testClass() {
        console.log('OTHER SERVICE CLASS USED');
      }
    }

    @Injectable()
    export class AnotherService extends BaseService {
      constructor(@InjectModel('Cat') public readonly catModel: Model<Cat>) {
        super(catModel);
      }
      testClass() {
        console.log('ANOTHER SERVICE CLASS USED');
      }
    }

这让我可以从我的提供商那里获得正确的服务(testClass() 打印出预期的字符串)。我的提供者如下所示:

    export const catProviders = [
      {
        provide: 'CatModelToken',
        useFactory: (connection: Connection) => connection.model('CAT', CatSchema),
        inject: ['DbConnectionToken'],
      },
      {
        provide: 'BaseService',
        useFactory: (ConfigService: ConfigService, connection: Connection) => {
          const options = ConfigService.get('SERVICE_TYPE');
          let model = connection.model('CAT', CatSchema);
          return new BaseService(model).createService(options);
      },
      inject: [ConfigService, 'CatModelToken', 'DbConnectionToken'],
      }
    ];

所以我的问题分为两部分:

  • 是否有更好的方法来处理正确类的创建和 避免必须为唯一创建一个BaseService 实例 打电话给createService()的目的是什么?
  • 将猫鼬模型注入新创建的服务的正确方法是什么?

我也不能使用文档中的 useClass 示例,因为我需要能够注入 ConfigService

【问题讨论】:

    标签: mongoose dependency-injection subclass extends nestjs


    【解决方案1】:

    你可以使用工厂方法解决这个问题,试试这个:

    确定服务“形状”的接口:

    export interface IDatabaseService {
        findOne(id: string): Promise<Cat>;
        count(): Promise<number>;
        testClass(): void;
    }
    

    BaseService 必须实现该接口:

    export class BaseService implements IDatabaseService {
    
        constructor(@InjectModel('Cat') public readonly catModel: Model<Cat>) {}
    
        async findOne(id: string): Promise<Cat> {
            return await this.catModel.findOne({_id: id});
        }
    
        async count(): Promise<number> {
            return await this.catModel.countDocuments();
        }
    
        testClass() {
            console.log('BASE SERVICE CLASS USED');
        }
    }
    

    动态服务未注入,因此它们不使用@Injectable() 装饰器:

    export class OtherService extends BaseService {
    
        constructor(@InjectModel('Cat') public readonly catModel: Model<Cat>) {
            super(catModel);
        }
    
        testClass() {
            console.log('OTHER SERVICE CLASS USED');
        }
    }
    
    export class AnotherService extends BaseService {
    
        constructor(@InjectModel('Cat') public readonly catModel: Model<Cat>) {
            super(catModel);
        }
    
        testClass() {
            console.log('ANOTHER SERVICE CLASS USED');
        }
    }
    

    工厂类是被注入的东西:

    @Injectable()
    export class DatabaseServiceFactory {
    
        constructor(@InjectModel('Cat') private readonly catModel: Model<Cat>) {}
    
        createService(name: string) : IDatabaseService {
            switch(name) {
                case 'other': return new OtherService(this.catModel);
                case 'another': return new AnotherService(this.catModel);
                default: throw new Error(`No service has been implemented for the name "${name}"`);
            }
        }
    }
    
    export const catProviders = [
        {
            provide: 'CatModelToken',
            useFactory: (connection: Connection) => connection.model('CAT', CatSchema),
            inject: ['DbConnectionToken'],
        },
        {
            provide: 'BaseService',
            useFactory: (ConfigService: ConfigService, connection: Connection, dbFactory: DatabaseServiceFactory) => {
    
                const options = ConfigService.get('SERVICE_TYPE');
                let model = connection.model('CAT', CatSchema);
                
                //return new BaseService(model).createService(options);
                return dbFactory.createService(options);
            },
            inject: [
                ConfigService,
                'CatModelToken',
                'DbConnectionToken',
                DatabaseServiceFactory
            ],
        }
    ];
    

    【讨论】:

    • 虽然此链接可能会回答问题,但最好在此处包含答案的基本部分并提供链接以供参考。如果链接页面发生更改,仅链接答案可能会失效。 - From Review
    猜你喜欢
    • 2020-09-09
    • 2016-06-22
    • 1970-01-01
    • 2014-06-05
    • 1970-01-01
    • 2020-04-26
    • 2011-12-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多