Использование профилей с nestjsx-automapper в nest. js - PullRequest
0 голосов
/ 27 апреля 2020

Я использую nestjsx-automapper (https://automapper.netlify.app/docs/usages/init/add-profile) от Chau Tran (спасибо за этот классный кусок кода). Я реализовал это, как показано в документации и как уже обсуждалось здесь: Как использовать профили из nartc / automapper в приложении nest js

Но у меня все еще есть проблема с доступом к AutoMapper из моего профиля class.

Вот мои настройки:

app.module.ts:

import { Module } from '@nestjs/common';
import { AppService } from './app.service';
import { MerchantModule } from './merchant/merchant.module';
import { TypeOrmModule } from '@nestjs/typeorm';
import { AutomapperModule, AutoMapper } from 'nestjsx-automapper';

@Module({
  imports: [
    TypeOrmModule.forRoot({
      ...
    }),
    AutomapperModule.withMapper(),
    MerchantModule
  ],
  providers: [],
  controllers: [],
})
export class AppModule {}

merchant.module.ts:

import { Module } from '@nestjs/common';
import { MerchantController } from './merchant.controller';
import { MerchantService } from './merchant.service';
import { TypeOrmModule } from '@nestjs/typeorm';
import { Merchant } from './entities/merchant.entity';
import { MerchantProfile } from './profiles/merchant.profile';
import { AutoMapper, AutomapperModule } from 'nestjsx-automapper';

@Module({
  imports: [TypeOrmModule.forFeature([Merchant]), AutomapperModule, MerchantProfile],
  exports: [TypeOrmModule],
  controllers: [MerchantController],
  providers: [MerchantService]
})
export class MerchantModule {}

merchant.profile.ts:

import {
  ProfileBase,
  Profile,
  AutoMapper
} from 'nestjsx-automapper';
import { Merchant } from '../entities/merchant.entity';
import { MerchantDto } from '../dto/merchant.dto';

@Profile()
export class MerchantProfile extends ProfileBase {
  constructor(
    private readonly mapper: AutoMapper) {
    super();
    mapper.createMap(Merchant, MerchantDto);
  }

    configure(): void {      
      return null;
    }
}

merchant.controller.ts:

import { Controller, Get, Param, Post, Body, Put, Delete } from '@nestjs/common';
import { MerchantService } from './merchant.service';
import { Merchant } from './entities/merchant.entity';
import { MerchantDto } from './dto/merchant.dto';
import { DeleteResult } from 'typeorm';
import { AutoMapper, InjectMapper } from 'nestjsx-automapper';

@Controller('merchant')
export class MerchantController {

    constructor(
        private merchantService: MerchantService,
        @InjectMapper() private readonly mapper: AutoMapper) { }

    @Get()
    public async findAll(): Promise<MerchantDto[]> {
        return this.mapper.mapArray(await this.merchantService.find(),MerchantDto);
    }
}

Когда я запускаю приложение с этой настройкой, я получаю следующее исключение: Nest не может разрешить зависимости AutomapperModule (?). Убедитесь, что аргумент AutomapperExplorer с индексом [0] доступен в контексте AutomapperModule.

Ответы [ 2 ]

2 голосов
/ 27 апреля 2020

AutoMapperModule.withMapper() в AppModule - это единственный раз, когда вам нужно использовать AutoMapperModule.

withMapper() создает синглетон AutoMapper, который будет доступен через @InjectMapper(), когда вы хотите использовать Mapper в Service (или любом Injectable).

Что касается Profile, следующий правильный синтаксис:

@Profile()
export class MerchantProfile extends ProfileBase {
  constructor(mapper: AutoMapper) { // no private readonly.
    super();
    mapper.createMap(Merchant, MerchantDto);
  }
  // no configure() method
}

Ниже приведен исходный код @nartc/automapper, в котором написано addProfile():

addProfile(profile: new (mapper: AutoMapper) => MappingProfile): AutoMapper {
    this._profileStorage.add(this, new profile(this));
    return this;
}

Вы можете видеть, что внутренне, @nartc/automapper будет создавать экземпляр (new profile()) и передавать экземпляр AutoMapper в конструктор профиля, чтобы он был доступен вам внутри Profile's constructor

Для этого кода в вашем MerchantModule

import { Module } from '@nestjs/common';
import { MerchantController } from './merchant.controller';
import { MerchantService } from './merchant.service';
import { TypeOrmModule } from '@nestjs/typeorm';
import { Merchant } from './entities/merchant.entity';
// import { MerchantProfile } from './profiles/merchant.profile';
// this is all you need which is to import the profile so TypeScript can execute it. Don't need `MerchantProfile` at all
import './profiles/merchant.profile';
import { AutoMapper, AutomapperModule } from 'nestjsx-automapper';

@Module({
  imports: [TypeOrmModule.forFeature([Merchant])], // don't need to import AutoMapperModule again. MerchantProfile is not a Module so you can't import it
  exports: [TypeOrmModule],
  controllers: [MerchantController],
  providers: [MerchantService]
})
export class MerchantModule {}

В вашем MerchantController:

@Controller('merchant')
export class MerchantController {

    constructor(
        private merchantService: MerchantService,
        @InjectMapper() private readonly mapper: AutoMapper) { }

    @Get()
    public async findAll(): Promise<MerchantDto[]> {
        // make sure `this.merchantService.find()` returns an Array of 
        // Merchant instances. If not, please provide an extra param to map()
        // return this.mapper.mapArray(await this.merchantService.find(),MerchantDto);
        return this.mapper.mapArray(await this.merchantService.find(), MerchantDto, Merchant); // notice the 3rd parameter is the Source model.
    }
}

Пожалуйста, дайте мне знать, если это работает для вас. Если нет, пожалуйста, создайте проблему в nestjsx-automapper репо и предоставьте воспроизводимый репозиторий, я посмотрю как можно скорее.

0 голосов
/ 27 апреля 2020

Я не слишком знаком с тем, как работает AutoMappModule, но похоже, что в вашем MerchantModule вы импортируете AutoMapperModule, тогда как вы должны импортировать AutoMapperModule.withMapper(), так же, как вы делал в AppModule.

...