2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

GraphQl + Typeorm @ManyToMany で作成された中間テーブルへのInsert、Deleteをするためのメモ

Last updated at Posted at 2021-09-08

GraphQl + Typeorm 周りはStackFlowを漁らないとわからないことが多すぎるため、メモを残す。

状況

・備品セットテーブルと、工具マスタテーブルで多対多のリレーションを持つ
・備品セットの中には複数の工具がある
・各エンティティのIDはDB INSERT 時のオートインクリメントで採番されるものとする

エンティティ

EquipmentSet(備品セット)

@ObjectType()
@Entity()
export class EquipmentSet {
    @Field()
    @PrimaryGeneratedColumn()
    id?: number

    @Field()
    @Column({ readonly: true })
    name: string = ""

    @Field(() => [Tool])
    @ManyToMany(() => Tool, (tool) => tools.equimentSets, {
        cascade: true,
    })
    @JoinTable()
    tools?: Tool[]

Tool(工具)エンティティ

@ObjectType()
@Entity()
export class Tool {
    @Field()
    @PrimaryGeneratedColumn()
    id?: number

    @Field()
    @Column()
    name: string = ''

    @Field(() => [EquipmentSet], { nullable: true })
    @ManyToMany(() => EquipmentSet, (equipmentSet) => equipmentSets.tools)
    equipmentSets?: EquipmentSet[]

エンティティを作成したら
migration:generateでマイグレーションファイルを作成。
migrate:runでテーブルを作成。
すると、EquipmentSets_Toolという中間テーブルが作成される。

EquipmentSets_Tool テーブル

  -- 列名は元になったテーブル名とカラム名の組み合わせで自動的に決定される
   Column1: equipmentSet_id,  -- PrimaryKey
   Column2: tool_id           -- PrimaryKey

コード

SELECTの場合

-- 内部では、equipmentSet テーブルに tool テーブル、中間テーブルのequipmentSet_toolテーブルをLEFT JOIN したSQLが発行されている。

    const toolInTheEquipmentSet = await getRepository(EquipmentSets).findOne({
        relations: ['tools', 'tools.equipments'], // お互いのリレーションを記載する
        where: { id: id },
    })
-- Tool 情報を持った EquipmentSets エンティティを取得できる
  // console.log(toolInTheEquipmentSet)
  // EquipmentSets { id, name, tools{[id:1, name:xxx,],[...]} }

INSERTの場合

getRepository() で指定できない中間テーブルへのINSERTを行いたい時

   //  let toolsNames:[] = ['ruler','screwdriver'] -- 検索項目が複数の場合
   // 中間テーブルの'tool_id'のために取得
       const tool = await getRepository(Tool).findOne({
        relations: ['equipmentSets'],
        where: { name: In(toolsNames)}, 
       })
   // -- tool { id:3,id:6 } 

   // EquipmentSetsテーブルへのINSERTデータ
       let eq: EquipmentSets = { name: "備品①", ... }
   
   // EquipmentSetsへの登録
       const createdEquipmentSets = await transactionalEntityManager.save(EquipmentSets, eq)
            eq = createdEquipmentSets
    -- console.log(createdEquipmentSets  )      
    -- createdEquipmentSets  { id:1 , name:"備品①"}
   
   // 中間テーブル用に tool エンティティに、createdEquipmentSets のオートインクリメントIDの値をセットしている
       for (const t of tool) {
         t.equipmentSets?.push(createdEquipmentSets)
       }
       
   // save(Tool)のため、Tool テーブルにINSERTしているように見えるが、
   // 実際は、EquipmentSet_Tool テーブルへのINSERTをしている 
    const createdEquipmentSetTool = await transactionalEntityManager.save(
                Tool,
                tool
       )

   //  --  発行されるSQL
   //  INSERT INTO `equipmentSet_tool`(`equipmentSet_id`, `tool_id`)
   //  VALUES (?, ?), (?, ?) -- PARAMETERS: [1,3, 1,6] 

  

DELETEの場合

中間テーブルから消したいレコードがある場合
ここがよくわかっていない、removeやdeleteを使用し、WHERE INのように複数指定できる方法があれば教えてください

      // 中間テーブルの equipment_id を指定しレコードを取得する。。
        const findEquipmentSetTool = await getRepository(EquipmentSet).find({
                relations: ['tools', 'tools.equipmentSet'],
                where: { id: 1 },
        })
        -- console.log(findEquipmentSetTool)
        -- findEquipmentSetTool { tool_id: [ 3, 6 ] }


      // findEquipmentSetTool には、tool_id情報が含まれている。
        for (const tool of findEquipmentSetTool.tools!) {
                const removedEquipmentSetTool = await getRepository(EquipmentSet)
                    .createQueryBuilder()
                    .relation(EquipmentSet, 'tools')
                    .of([{ id: 1 }])      // 中間テーブルのequipmentSet_id を指定している。
                    .remove([{ id: 3 }])  // 中間テーブルのtool_id を指定している。 2回目は 6 が入る
        }
2
1
1

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
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?