[TypeORM] One to Manyのsaveメソッドで不要になった子オブジェクトを自動で消す

NO IMAGE

TypeORMで、One to Manyのリレーションを使う時、子のオブジェクトもまとめて登録・更新したい時は、以下のように記述するかと思います(コードはあくまでイメージです)。

前提:idが1、2のbookが既に存在している

user = {
   name: "User 1",
   books: [
       {
           name: "Book A",
       },
       {
            id: 2
            name: "Book B",
       }
    ]
}

await userRepository.save(user)

この時、bookテーブルの各レコードへの期待する動作としては、以下のようになると思います。

  • id1:削除
  • id2:更新
  • id3:新規作成

ただ、TypeORMのデフォルトの挙動では、id1が削除されるのではなく、userへの外部キーがnullとなり、レコード自体はテーブルに残ってしまいます。

外部キーにnot null制約をかけていると、例外となってしまいますし、結構いまいちな挙動です。ということで、私も以前はめんどくさいなと思いながらも、レコードにあるidとリクエストで渡ってくるidの比較をして、存在しなくなっているidのレコードは事前に削除する、といった処理を記述していました。

何か良い方法はないかなと思って見ていたところ、2020年の11月に上記処理をいい感じにやってくれるよう修正されているようです!

https://github.com/typeorm/typeorm/issues/1351

上記のissueに記載されている通り、orphanedRowActionという設定が可能となっており、デフォルトのnullifyからdeleteに変更してあげれば良いです。これによって、Userとの紐づけが切れた時に自動的に物理削除されます。

具体的には、子オブジェクトのエンティティ(今回で言うとBook)に以下のように記述します。

@Entity()
export class Book {
  // orphanedRowAction: 'delete' を設定する
  @ManyToOne(() => User, { orphanedRowAction: 'delete' })
  user: User

  /* ... */
}

これで、期待する挙動になるはずです。