TypeORMでEntityを定義するHow-To

# 概要
TypeORMでEntityを定義するHow-Toを社内の勉強会用に作成してみました！

これから導入される方や初めて使う方の一助になれば幸いです


# TypeORM is 何？
> TypeORMは、NodeJS、Browser、Cordova、PhoneGap、Ionic、React Native、NativeScript、Expo、Electronの各プラットフォームで動作し、TypeScriptとJavaScript(ES5, ES6, ES7, ES8)で使用できるORMです。その目的は、常に最新のJavaScript機能をサポートし、いくつかのテーブルを持つ小規模なアプリケーションから、複数のデータベースを持つ大規模なエンタープライズアプリケーションまで、データベースを使用するあらゆる種類のアプリケーションの開発を支援する追加機能を提供することです。

# 今回使用するモジュールとサービス
| サービス | 説明 |
|-----------|------------|
| Column|テーブルカラム|
| PrimaryGeneratedColumn|自動増減の主キーカラム|
| CreateDateColumn|データ挿入時に自動で設定されるカラム|
| Timestamp |カラムのデータ型で使用|
| UpdateDateColumn |データ更新時に自動で設定されるカラム|
| Entity |クラスがEntityであることを定義|
| OneToMany |1対多/多対1の関係を定義するカラム|
| OneToOne |1対1の関係を定義するカラム|
| JoinColumn |外部キーを持つカラムを定義する|

```
import {
    Column,
    PrimaryGeneratedColumn,
    CreateDateColumn,
    Timestamp,
    UpdateDateColumn,
    DeleteDateColumn,
    Entity,
    OneToMany,
    OneToOne,
    JoinColumn,
  } from 'typeorm'
```

https://github.com/typeorm/typeorm/blob/master/docs/decorator-reference.md#primarycolumn

1対多・１対1がピントこない方はこちらを参照ください

https://orkhan.gitbook.io/typeorm/docs/many-to-one-one-to-many-relations

https://orkhan.gitbook.io/typeorm/docs/one-to-one-relations

# Entityを定義

<details><summary>サンプルコード</summary><div>

```
import {
    Column,
    PrimaryGeneratedColumn,
    CreateDateColumn,
    Timestamp,
    UpdateDateColumn,
    DeleteDateColumn,
    Entity,
    OneToMany,
    OneToOne,
    JoinColumn,
  } from 'typeorm'

  @Entity('contractors')
  export class Contractor {
    @PrimaryGeneratedColumn({
      name: 'id',
      unsigned: true,
      type: 'smallint',
      comment: '契約ID',
    })
    readonly id: number
  
    @Column('varchar', { comment: '会社名' })
    organization_name: string
  
    @CreateDateColumn({ comment: '登録日時' })
    readonly ins_ts?: Timestamp
  
    @Column('varchar', { comment: '登録者', nullable: true })
    ins_admin_user_id: string | null = null
  
    @UpdateDateColumn({ comment: '最終更新日時' })
    readonly upd_ts?: Timestamp
  
    @Column('varchar', { comment: '更新者', nullable: true })
    upd_admin_user_id: string | null = null
  
    @DeleteDateColumn({ comment: '削除日時' })
    readonly delete_ts?: Timestamp
  
    @Column('varchar', { comment: '削除者', nullable: true })
    delete_admin_user_id: string | null = null
    
    @OneToOne(() => Plan, (plan) => plan.contractor, {
      createForeignKeyConstraints: false,
      persistence: false,
    })
    @JoinColumn({
      name: 'plan_id',
      referencedColumnName: 'id',
    })
    readonly plan?: Plan

    @OneToMany(() => Terminal, (terminal) => terminal.contractor, {
      createForeignKeyConstraints: false,
      persistence: false,
    })
    readonly terminals?: Terminal[]
  
    constructor(
      organization_name: string,
      ins_admin_user_id: string | null,
      upd_admin_user_id: string | null,
      delete_admin_user_id: string | null,
      plan_id: number,
    ) {
      this.organization_name = organization_name
      this.ins_admin_user_id = ins_admin_user_id
      this.upd_admin_user_id = upd_admin_user_id
      this.delete_admin_user_id = delete_admin_user_id
      this.plan_id = plan_id
    }
  }
```
</div></details>

:::note info
作成するテーブル名を定義してください
:::
```
@Entity('contractors')
```

:::note info
unsigned：UNSIGNED属性を数値列に付与します（MySQL限定）
comment:カラム名の説明です。誰でもEntityを読めばカラムの役割を理解できるように推奨してます
readonly:読み取り専用のカラムに付与します。自動増減のカラムは書き換えて欲しくないので設定
:::
```
    @PrimaryGeneratedColumn({
      name: 'id',
      unsigned: true,
      type: 'smallint',
      comment: '契約ID',
    })
    readonly id: number
```

:::note info
nullable:NULLを許容します
ins_admin_user_id:xxx| null = null ：実行時のプロパティがNULLの場合に不一致になるのを防ぐ
:::
```
    @Column('varchar', { comment: '登録者', nullable: true })
    ins_admin_user_id: string | null = null
```
[こちらを参考にさせていただきました](https://tech.bitbank.cc/typeorm-entity-guideline/)


:::note info
1対1の関係を定義します
1つのcontractor(契約）は1つのplan（契約プラン）のみ設定する仕様とします
createForeignKeyConstraints:外部キー制約の作成を回避します
persistence:エンティティの保存中に複数の余分なクエリが回避されるため、パフォーマンスの最適化に役立ちます。
:::
```
    @OneToOne(() => Plan, (plan) => plan.contractor, {
      createForeignKeyConstraints: false,
      persistence: false,
    })
    @JoinColumn({
      name: 'plan_id',
      referencedColumnName: 'id',
    })
    readonly plan?: Plan

/*
  // 契約プランのEntity定義
   @OneToOne(() => Contractor, (contractor) => contractor.plan, {
    createForeignKeyConstraints: false,
    persistence: false,
  })
  readonly contractor?: Contractor
*/
```

https://typeorm.delightful.studio/interfaces/_decorator_options_relationoptions_.relationoptions.html#persistence


:::note info
1対多/多対1の関係を定義します
1つのcontractor(契約）は1つ以上の端末(terminal)を申請する仕様とします
createForeignKeyConstraints:外部キー制約の作成を回避します
persistence:エンティティの保存中に複数の余分なクエリが回避されるため、パフォーマンスの最適化に役立ちます。
:::
```
    @OneToMany(() => Terminal, (terminal) => terminal.contractor, {
      createForeignKeyConstraints: false,
      persistence: false,
    })
    readonly terminals?: Terminal[]

/*
  // 端末のEntity定義
  @ManyToOne(() => Contractor, (contractor) => contractor.terminals, {
    createForeignKeyConstraints: false,
    persistence: false,
  })
  @JoinColumn({
    name: 'contractor_id',
    referencedColumnName: 'id',
  })
  readonly contractor?: Contractor
*/
```

:::note info
初期値のあるプロパティを除いてオブジェクトの不変条件を満たすためにconstructorを設定します
:::
```
  constructor(
    name: string,
    terminal_activate_possible_count: number,
    license_period_days: number,
    archive_period_days: number,
    ins_admin_user_id: string | null,
    upd_admin_user_id: string | null,
    delete_admin_user_id: string | null,
    delete_flg: boolean
  ) {
    this.name = name
    this.terminal_activate_possible_count = terminal_activate_possible_count
    this.license_period_days = license_period_days
    this.archive_period_days = archive_period_days
    this.ins_admin_user_id = ins_admin_user_id
    this.upd_admin_user_id = upd_admin_user_id
    this.delete_flg = delete_flg
    this.delete_admin_user_id = delete_admin_user_id
  }
```

以上でEntityの定義が完了です！


# 参考文献

https://typeorm.io/#/

https://github.com/typeorm/typeorm/blob/master/docs/decorator-reference.md

https://tech.bitbank.cc/typeorm-entity-guideline/

# 最後に

読んでいただきありがとうございます。
今回の記事はいかがでしたか？
・こういう記事が読みたい
・こういうところが良かった
・こうした方が良いのではないか
などなど、率直なご意見を募集しております。