0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

class-transformer を使ってネストしたエンティティをDTOに変換する

Last updated at Posted at 2025-01-04

nestjs で TypeORM とかのfetch結果を nextjs から取得するって場合、エンティティをそのまま返してもいいのだけど n:n な関連は 1:n に置き換えたほうがフロントエンドで扱いやすいので適当なDTOに詰め替えてから返す、って操作はありがち。

しかしそんな操作をいちいち手書きしているととても面倒なので class-transformer とか使う。

エンティティ定義

Book, BookGenre, Genre による n:n 構造を作る。

@Entity("books")
export class Book {
    @PrimaryGeneratedColumn()
    id: number;

    @Column()
    title: string;

    @Column()
    author: string;

    @Column('text')
    description: string;

    @Column()
    publishedYear: number;

    @Column()
    genre: string;

    @OneToMany(() => BookGenre     , bookGenre => bookGenre.book)
    bookGenres: BookGenre[];
}

@Entity()
export class BookGenre {
    @PrimaryGeneratedColumn()
    id: number;

    @ManyToOne(() => Book, book => book.bookGenres)
    book: Book;

    @ManyToOne(() => Genre, genre => genre.bookGenres)
    genre: Genre;
}

@Entity()
export class Genre {
    @PrimaryGeneratedColumn()
    id: number;

    @Column()
    name: string;

    @OneToMany(() => BookGenre, bookGenre => bookGenre.genre)
    bookGenres: BookGenre[];
}

DTO

構造を単純にするために BookDto, GenreDto の2つにしぼり、 1:n の構造を作る。

export class BookDto {

    @Expose()
    id: number;
    @Expose()
    title: string;
    @Expose()
    author: string;
    @Expose()
    publishedYear: number;
    @Expose()
    description: string;
    
    @Expose({ name: 'bookGenres' })
    @Type(() => GenreDto)
    @Transform(({ obj }) => 
        obj.bookGenres.map((bookGenre: BookGenre) => plainToInstance(GenreDto, bookGenre.genre))
      )
    genres: GenreDto[];

}

Transform で bookGenres:BookGenre[] を genre:GenreDto[] に展開する。

変換

        const books = await this.repos.find({
            relations: ['bookGenres', 'bookGenres.genre'],
            order: { id: 'ASC' },
        });
        const dto = plainToInstance(BookDto, books);

変換はこれだけ。

その他

AutoMapper を使おうとしたけど pojos ストラテジーではベースのプロパティも forMember() ですべて記述する必要があるみたいで、さすがにそれだったら books.map(...) したほうがましだと思って不採用とした。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?