EntityFramework Coreで爆速データベース設計

こんにちは。

テックリードのTerukiです。

[先週の記事](https://qiita.com/omt_teruki/items/7aa6db2530c8dad3dafa)ではXにてかなり反響があり、普段よりも10倍以上のアクセスがあり嬉しいです。
今後もC#など.NET系の発信もしていきたいと思います。

今回はOh my teethで活用しているEF Coreの使い方について紹介します。

# TL;DR
- 完璧なERを最初から目指さない
- マイグレーション機能をフル活用してERの問題箇所を後から修正
- 本番リリース前はレビューをしっかり

# EntityFramework Core
[公式の紹介](https://github.com/dotnet/efcore)を引用してみます。

>EF Core is a modern object-database mapper for .NET. It supports LINQ queries, change tracking, updates, and schema migrations. EF Core works with SQL Server, Azure SQL Database, SQLite, Azure Cosmos DB, MariaDB, MySQL, PostgreSQL, and other databases through a provider plugin API.

めちゃくちゃ雑に言うと便利なORMです。便利。
いわゆるDBデータを.NETのPOCOクラスにマッピングする機能以外にも、LINQによるクエリビルディングやチェンジトラッカーによる更新、マイグレーション機能なども含んでいます。

# ORMの是非
今回の記事ではデータベース設計に焦点を当てたいのでORM自体の是非にはふれませんが一言だけ言及しておくと、Oh my teethではコードレビュー時にインデックスを考慮されたクエリが生成されるかレビュアーがレビューします。

(そもそもLINQのクエリを見ただけで生成されるSQLを想像できるメンバーがレビューしているので、ORMを使うことによって生じる諸問題は基本発生しません:muscle: )


# コードファーストによるデータベース設計
EF Coreによるコードファーストとは、下記のようなエンティティクラスを作成してその内容からDDLを生成するアプローチのことです。

```cs
public class Post {
    public int Id { get; set; ]

    [StringLength(255)
    public required string Title { get; set; }

    public string? Content { get; set; }
    // ・・・
}
```

生成されるDDLイメージ

```sql
CREATE TABLE `Post` (
    `Id` bigint unsigned NOT NULL AUTO_INCREMENT,
    `Title` varchar(255) NOT NULL,
    `Content` longtext NULL
);
```

SELECT文なら何も見ずにすらすら書けますが、CREATE TABLEを何も見ずにすらすら書ける人はなかなか居ないのではと思います。私にはちょっと厳しい。

一方上記のエンティティクラスはC#に慣れているならすらすら書けますね。

このくらいのテーブルではなんとも言えないですが、カラム数やテーブル数が増えると非常に重宝します。

# データベース設計の難しさ
なにかプロダクトを作ろうとなった場合、データベース設計はかなり初期の段階で行われると思います。

作りたいプロダクトの規模が大きければ大きいほど設計には時間がかかります。

スピード重視なスタートアップ企業においてはPDCAをはやく回したいので、設計フェーズで数ヶ月など大量に時間を投下することはしたくありません。

# 完璧を諦める
完璧なデータベースを設計できることに越したことはありませんが、大抵の場合は実装時に「あ！これじゃダメじゃん:sob:」となりがちです。

今までにもそういった場面は何度もありましたが、かといってスピードは重視したいです。

そこで、最初から100点のテーブルを作ろうとはせずにある程度できたら実装を始めてしまいます。
実装を進めていくと、当初想定していたERではダメなことに気づいたりカラムが足りなかったりインデックスが足りなかったりといろいろ問題が発生します。

実際に実装を始めたらすぐ分かりそうな問題でも、一切実装を書かずに発見するのはなかなか難しいですし時間がかかりますよね。

EF Coreのマイグレーション機能でエンティティクラスの変更をトラックして、ERを変更するためのALTER TABLEやCREATE INDEXなどのDDLを生成させることができるので後から容易に修正ができます。

長々と書きましたがようは「ERを見ながら唸ってる時間があったらとっとと実装を書いてしまって問題が発生したらその都度修正するようにしようよ」ということです。

※もちろん後から修正する数を最小限に抑えるのは設計者の腕の見せ所です:muscle: 


# レビュープロセス
いくらマイグレーションがあるからといって雑なERを量産して良いわけではありません。

最終的にリリースされるERが洗練されたものでなければ<font color="orange">後継者に恨まれる原因</font>となります。

EF Coreでは、下記のコマンドで実際にマイグレーションが生成するDDLを出力できます。

```sh
dotnet ef migrations script
```

Oh my teethではマイグレーションファイルと一緒にDDLもGitHubのプルリクエストに載せてレビュー対象とすることで雑なERがマージされることを防いでいます。

DDLレビューでvarcharの文字数が不適切だったり想定していた型になっていなかったりなど気付けるので意外と重要です。

# おわりに
今回は文字ばっかりの記事になってしまいましたが、Oh my teethのデータベース設計について紹介しました。

すべての組織においてこのやり方が良いわけではないと思いますが、少なくともスピード重視の組織にはマッチするのではないかなと思います。

最初に数週間かけてERの設計をするのではなく、2日で一旦完成させてすぐ実装に移ってしまったほうが結果的にはやくプロダクトをリリースできると思います。

ただ、本番リリース後は迂闊に変更できなくなるので最終形のレビューはしっかりやったほうが良いです。

次回以降EF Coreの他の部分についても紹介できたらなと思います。

では。

# Oh my teethについて
Oh my teethでは未来の歯科体験を創るために日々活動しています。

Techチームではより良いユーザー体験を提供するべく、Webフロントエンドからバックエンド、スマホアプリに機械学習モデルなど、さまざまなプロダクトを開発しています。

一緒に未来の歯科体験を創りませんか？興味がある方は是非こちらを確認してください。

https://oh.careers/

カジュアル面談も可能なので気軽に応募してみてください！

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3192685/0138b492-e02b-852e-61fa-fc065b53d285.png" width="450" />