当前位置: 首页 > 知识库问答 >
问题:

NestJs-DTO和实体

郦昆
2023-03-14

我试图在我的项目中巧妙地使用DTO和实体,但它似乎比它应该的更复杂。我正在构建一个管理库存的后端,我使用NestJs和TypeOrm。

我的客户向我发送了一组数据抛出POST请求,比如:

{
  "length": 25,
  "quantity": 100,
  "connector_A": {
    "id": "9244e41c-9da7-45b4-a1e4-4498bb9de6de"
  },
  "connector_B": {
    "id": "48426cf0-de41-499b-9c02-94c224392448"
  },
  "category": {
    "id": "f961d67f-aea0-48a3-b298-b2f78be18f1f"
  }
}

我的控制器有责任通过使用自定义ValidationPipe检查字段:

@Post()
  @UsePipes(new ValidationPipe())
  create(@Body() data: CableDto) {
    return this.cablesService.create(data);
}

我在许多地方读到,在最佳实践中,原始数据应该转换为DTO,当涉及到数据插入时,我应该将DTO转换为类型化实体。

我同意这种方法,但我发现它非常复杂,当我的表和前缀名词之间存在关系时,情况更为复杂。

这是我的实体电报

@Entity('t_cable')
export class Cable {

  @PrimaryGeneratedColumn('uuid')
  CAB_Id: string;

  @Column({
    type: "double"
  })
  CAB_Length: number;

  @Column({
    type: "int"
  })
  CAB_Quantity: number;

  @Column()
  CON_Id_A: string

  @Column()
  CON_Id_B: string

  @Column()
  CAT_Id: string

  @ManyToOne(type => Connector, connector => connector.CON_Id_A)
  @JoinColumn({ name: "CON_Id_A" })
  CON_A: Connector;

  @ManyToOne(type => Connector, connector => connector.CON_Id_B)
  @JoinColumn({ name: "CON_Id_B" })
  CON_B: Connector;

  @ManyToOne(type => Category, category => category.CAB_CAT_Id)
  @JoinColumn({ name: "CAT_Id" })
  CAT: Category;

}

这是我的电缆交互DTO:

export class CableDto {

  id: string;

  @IsOptional()
  @IsPositive()
  @Max(1000)
  length: number;
  quantity: number;

  connector_A: ConnectorDto;
  connector_B: ConnectorDto;
  category: CategoryDto

  public static from(dto: Partial<CableDto>) {
    const it = new CableDto();
    it.id = dto.id;
    it.length = dto.length;
    it.quantity = dto.quantity;
    it.connector_A = dto.connector_A
    it.connector_B = dto.connector_B
    it.category = dto.category
    return it;
  }

  public static fromEntity(entity: Cable) {
    return this.from({
      id: entity.CAB_Id,
      length: entity.CAB_Length,
      quantity: entity.CAB_Quantity,
      connector_A: ConnectorDto.fromEntity(entity.CON_A),
      connector_B: ConnectorDto.fromEntity(entity.CON_B),
       category: CategoryDto.fromEntity(entity.CAT)
    });
  }

  public static toEntity(dto: Partial<CableDto>) {
    const it = new Cable();
    if (dto.hasOwnProperty('length')) {
      it.CAB_Length = dto.length;
    }
    if (dto.hasOwnProperty('quantity')) {
      it.CAB_Quantity = dto.quantity;
    }
    if (dto.hasOwnProperty('connector_A')) {
      it.CON_Id_A = dto.connector_A.id;
    }
    if (dto.hasOwnProperty('connector_B')) {
      it.CON_Id_B = dto.connector_B.id;
    }
    if (dto.hasOwnProperty('category')) {
      it.CAT_Id = dto.category.id;
    }
    return it;
  }
}

我知道这三种在DTO和Entite两个方向上转换的方法感觉非常脏,这就是我来这里的原因。。

我的简单创建或获取请求服务了解:

async create(dto: CableDto): Promise<CableDto> {
  const cable = await this.cablesRepository.save(CableDto.toEntity(dto));
  return await this.findById(cable.CAB_Id)
}

我相信有一个更简单的解决方案来实现这一点,或者至少有一个正确的方法来实现这一点。

有什么想法吗?

非常感谢。

共有2个答案

沈俊明
2023-03-14

您可以使用Automapper来完成实体和DTO之间的所有转换。

我在许多项目中使用它,效果很好,特别是在有许多DTO和实体的项目中。

例如,你可以这样做:

    export class InitializeMapper {
        mapper: AutoMapper;
    
        constructor() {
            this.mapper = new AutoMapper();
    
            this.mapper.createMap(CableDto, CableEntitt)
                .forMember(dst => dst.length, mapFrom(s => s.length))
                .forMember(dst => dst.quantity, mapFrom(s => s.quantity))
                .forMember(dst => dst.connector_A, mapFrom(s => s.connector_A.id))
                .forMember(dst => dst.connector_B, mapFrom(s => s.connector_B.id))
                .forMember(dst => dst.connector_C, mapFrom(s => s.connector_C.id));
            });
        }
        
        map(a: any, b: any) {
            return this.mapper.map(a, b);
        }
    
        mapArray(a: Array<any>, b: any) {
            return this.mapper.mapArray(a, b);
        }
    }

因此,您可以在项目中的任何地方重用相同的映射。

当做

易宏阔
2023-03-14

对于所有类型转换(例如DTO

因此,在您的情况下,使用typerORM:

  1. npm install --save @fabio.formosa/metamorphosis-nest
    
    import { MetamorphosisNestModule } from '@fabio.formosa/metamorphosis-nest';
    
    @Module({
      imports: [MetamorphosisModule.register()],
      ...
    }
    export class MyApp{ }
    
    import { Convert, Converter } from '@fabio.formosa/metamorphosis';
    
    @Injectable()
    @Convert(CableDto, Cable)
    export default class CableDtoToCableConverter implements Converter<CableDto, Promise<Cable>> {
    
    constructor(private readonly connection: Connection){}
    
    public async convert(source: CableDto): Promise<Cable> {
      const cableRepository: Repository<Cable> = this.connection.getRepository(Cable);
      const target: Product | undefined = await cableRepository.findOne(source.id);
      if(!target)
        throw new Error(`not found any cable by id ${source.id}`);
      target.CAB_Length = source.length;
      target.CAB_Quantity = source.quantity;
      ... and so on ...
      return target;
    }
    

    }

    最后,您可以根据需要注入和使用conversionService:

     const cable = <Cable> await this.convertionService.convert(cableDto, Cable);
    

    从电缆到电缆的转换器更简单。

    获取自述文件,了解示例和变形nestjs的所有好处。

 类似资料:
  • 我正在尝试将复杂的实体转换为Dto。我想从DTO中删除实体中的一些值。 我的实体看起来像这样(为了简单起见,省略了实体的大部分): 我找到了一个对简单实体非常有效的解决方案:将实体转换为数据。如果我采纳了自定义拦截器的建议,删除id或整个item属性就可以了。 我尝试了两种方法来定义我的DTO: < li >它仅返回id和整个项目。 现在的问题是我只想删除 item 属性中的某些值。例如,私有字段

  • 问题内容: 我们将使用DTO在表示层之间来回发送数据。我们有像这样的图层: facade appService domain 并且我们使用推土机来帮助我们将实体转换为dto。但是我现在有两个问题: 从实体到dto,我们可以使用推土机,但是从dto到实体,我们可以使用推土机吗?如果是,如何? 我应该在哪里创建实体?在外观或DTOAssembler中? 例如,我必须注册一本书。这本书的实体外观如下:

  • 问题内容: 我是Go语言的新手,具有C#背景并且对如何构造Go应用程序感到困惑。 假设我正在构建一个REST API,它将位于数据库之上。还要说,即使完成后,鉴于业务的变迁等,此应用程序可能仍需要频繁更改。 在带有诸如Entity Framework和DTO之类的工具的C#中,我通过从控制器给出的结果中抽象出数据库来缓解此问题。如果更改数据库中一堆字段的名称,则可能必须更改数据库访问逻辑,但是希望

  • 我需要一种标准方法来比较JPA实体与其DTO并确定它们是否代表相同的业务对象。我可以想到三种方法,每个DTO上的自定义方法,带有静态方法的接口或比较器。 基于若昂·迪亚斯的回答,方法4-继承。 优点/缺点 方法1-一路坏 方法2-使用接口支持组合而不是继承,但需要使用自定义方法名称的语义学() 方法3-不需要修改源代码 方法4-简化语义学,因为它使用标准但需要“样板 这些方法的任何其他优缺点或对其

  • 如果我有实体类 和一个DTO > 我的问题是我应该在客户端中使用(赢形)吗?或创建另一个类 如果我想要一个方法 我应该把它放在哪里(作为静态的辅助方法,还是放在里面)?我以前认为应该是里面的方法,但是贫血模型不允许有任何方法。

  • 我有一个实体像下面在Nestjs应用程序与typeorm为mongoDB: 我的其他实体扩展了审计,在我的应用程序中,我使用jwt来验证用户。 问题是,当我想保存一个实体,我不知道如何设置createdBy与@Before插入钩子... 我知道请求中有用户,但我不知道将用户引入方法的正确方法是什么?