高瀬博道の技術ブログ

高瀬博道の技術ブログです。

NestJS でデータベース操作できるようにする - 2

前回

takasehiromichiex.com

ユーザモジュールへのEntityの紐付け

ユーザモジュールへEntityを紐づけます。

src/user/user.module.ts
import { Module } from "@nestjs/common";
import { UserService } from "./user.service";
import { UserController } from "./user.controller";
import { TypeOrmModule } from "@nestjs/typeorm";
import { User } from "./entities/user.entity";

@Module({
  imports: [TypeOrmModule.forFeature([User])],
  controllers: [UserController],
  providers: [UserService],
})
export class UserModule {}

TypeOrmModule.forFeature([User])を追加しました。

これで、@InjectRepositoryを使用して、サービスにリポジトリをDIできるようになりました。

サービスを修正します。

src/user/user.service.ts
import { Injectable } from "@nestjs/common";
import { InjectRepository } from "@nestjs/typeorm";
import { DeleteResult, Repository } from "typeorm";
import { CreateUserDto } from "./dto/create-user.dto";
import { UpdateUserDto } from "./dto/update-user.dto";
import { User } from "./entities/user.entity";

@Injectable()
export class UserService {
  constructor(
    @InjectRepository(User) private userRepository: Repository<User>
  ) {}

  create(createUserDto: CreateUserDto) {
    return "This action adds a new user";
  }

  findAll(): Promise<User[]> {
    return this.userRepository.find();
  }

  findOne(id: number): Promise<User> {
    return this.userRepository.findOneBy({ id });
  }

  update(id: number, updateUserDto: UpdateUserDto) {
    return `This action updates a #${id} user`;
  }

  async remove(id: number): Promise<DeleteResult> {
    return await this.userRepository.delete(id);
  }
}

リレーション

リレーションは2つ以上のテーブル間で確立される関連づけですが、以下の3つのタイプがあります。

One-to-one

主テーブルの全ての行には、外部テーブルに関連づけられた行が1つだけあります。

@OneToOne()デコレータを使用して、このタイプの関係を定義します。

One-to-many / Many-to-one

主テーブルの全ての行には、外部テーブルに関連づけられた行が1つ以上あります。

@OneToMany()デコレータと、@ManyToOne()デコレータを使用して、このタイプの関係を定義します。

Many-to-many

主テーブルの全ての行には、外部テーブルに関連づけられた行が1つ以上あり、外部テーブルの全ての行には、主テーブルに関連づけられた行が1つ以上あります。

@ManyToMany()デコレータを使用して、このタイプの関係を定義します。

まず、エンティティを作成します。

src/photo/entities/photo/entity.ts
import { User } from "src/user/entities/user.entity";
import { Column, Entity, ManyToOne, PrimaryGeneratedColumn } from "typeorm";

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

  @Column()
  url: string;

  @ManyToOne(() => User, (user) => user.photos)
  user: User;
}

このエンティティを使用して、ユーザエンティティにOne-to-Manyのリレーションを定義します。

src/user/entities/user.entity.ts
import { Photo } from "src/photo/entities/photo.entity";
import { Column, Entity, OneToMany, PrimaryGeneratedColumn } from "typeorm";

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

  @Column()
  firstName: string;

  @Column()
  lastName: string;

  @Column({ default: true })
  isActive: boolean;

  @OneToMany(() => Photo, (photo) => photo.user)
  photos: Photo[];
}

ユーザモジュールの定義も変更します。

src/user/user.module.ts
import { Module } from "@nestjs/common";
import { UserService } from "./user.service";
import { UserController } from "./user.controller";
import { TypeOrmModule } from "@nestjs/typeorm";
import { User } from "./entities/user.entity";
import { Photo } from "src/photo/entities/photo.entity";

@Module({
  imports: [TypeOrmModule.forFeature([User, Photo])],
  controllers: [UserController],
  providers: [UserService],
})
export class UserModule {}

エンティティの自動読み込み

ルートモジュールを以下のように設定することで、エンティティが自動で読み込まれるようになります。

src/app.module.ts
import { MiddlewareConsumer, Module, NestModule } from "@nestjs/common";
import { TypeOrmModule } from "@nestjs/typeorm";
import { AppController } from "./app.controller";
import { AppService } from "./app.service";
import { CatsController } from "./cats/cats.controller";
import { CatsModule } from "./cats/cats.module";
import { logger } from "./middleware/logger/logger.middleware";
import { UserModule } from "./user/user.module";

@Module({
  imports: [
    TypeOrmModule.forRoot({
      type: "mysql",
      host: "localhost",
      port: 3306,
      username: "root",
      password: "root",
      database: "test",
      synchronize: true,
      autoLoadEntities: true,
    }),
    CatsModule,
    UserModule,
  ],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule implements NestModule {
  configure(consumer: MiddlewareConsumer) {
    consumer.apply(logger).forRoutes(CatsController);
  }
}

autoLoadEntities: trueを追加しました。

まとめ

ここまでで、

  • ユーザモジュールへのEntityの紐付けについて
  • リレーションについて
  • エンティティの自動読み込みについて

を学びました。

次回も、データベース操作を掘り下げようと思います。

コード

今回のコードは、以下に格納しました。

github.com

takasehiromichiex.com