こんにちは、バッヂーです。
先日、YouTubeのホーム画面に気になる動画がありましたのでちょっと見始めたら、興味深くて結局最後まで見てしまったものがありましたので紹介させてください。次の動画です。
なんとも笑顔がステキなおっちゃん(お名前はTim Coreyさんです)です。中身はもちろんちゃんとした動画です。
タイトルは「Entity Framework Best Practices - Should EFCore Be Your Data Access of Choice?」です。「EFCoreをデータアクセスとしてシステムに利用するのは最適な選択なのか?」を考察している動画です。
私はいちおう仕事でC#やASP.netやEntity Frameworkを使用しておりますが、ここらへんを胸張って朗々と説明できるほど詳しくはありません。なのでとりあえず次の説明だけしておきます。
Entity Frameworkとはなんぞや? 次の特徴があります(と思ってます)。
- とりあえず「データベースはこんな感じかな?」で開発をはじめても、後から修正がラクにできる。
- データベースへの接続や切断があんまりめんどくさくない。
- データベースを操作するSQLにガッツリ詳しくなくても操作できる
要はWebアプリなどでデータベースにデータを保持する必要があるときに、データベースとのやりとりをわかりやすくしてくれているもの、とでも考えてください。
動画の要約みたいなもの
この動画で語られていることで、面白いなと思ったことをかいつまんでみます。
- ASP.NET Coreのプロジェクトをつかって、Entity Framework Core(以下、EFCore)を使ってみる。
- 最初のテーブルの作成や、フィールドの属性を変更したときのEFCoreのMigrationの挙動とコードを説明。
- String型の属性で長さを指定しなければ、SqlServerではnvarchar(max)となる。
- nvarchar(max)にはインデックスの問題がある。
- このテストではnvarchar(max)のメモリ使用量は272kb で、nvarchar(64)だと5kb以下。これは開発環境や同時利用者が少人数の場合は問題にならないが、本番環境で利用者が増えてくると致命的なトラブルのもとになりかねない。
- Linqのメソッド構文のwhere句で自作の関数が使えるが、EFの機能にないのでエラーがでる。ToList()などListにした後はC#の機能になるのでwhere句で自作の関数が使える。
- ところが上記の使い方だととんでもない量のデータをDBから取得することがある。これも開発環境では良いが、利用者が増えるとパフォーマンスに致命的な影響を与えかねない。
- EFCoreを使用する利点と欠点。
- 開発が速い。
- SQLについてあまり知らなくて良い。
- しかし上記はパフォーマンスと反比例している。システムが大きくなると「開発はスローダウン」「SQLの十分な理解」が必要になってくる。
- Dapperを使う利点と欠点。※Tim CoreyさんはDapperの方が好みのようです。
- 製品版でのパフォーマンスが良い。
- SQLを知っている人にはDapperの方がわかりやすい。
- しかしもちろんSQLの知識が必要。
- EFCoreを使うなら、どのようなSQLを生成してどのような挙動をするのかをを理解して、EFCoreのエキスパートになるべくたくさん試してみることを強くおすすめします(※と、Timさんはおっしゃってる)。
以前に悩んだことを思い出した
Linqでは自作関数をwhere句に使えます。この動画でも1:58:30あたりから触れております。こんな感じです。
private void OnGet()
{
using(ApexContext db = new ApexContext())
{
var legends = db.ApexLegends
//.Where(x => x.PassiveAbility.Contains("Shield"))
.Where(x => HasShieldInPassiveAbility(x.PassiveAbility))
.ToList();
}
}
private bool HasShieldInPassiveAbility(string ability)
{
return ability.Contains("Shield");
}
ただしこれは実際に実行するとエラーがでます。
なぜなら7行目のWhere句はSqlServerの機能ではないからです。Where句の中にあるHasShieldInPassiveAbilityはC#のコードだからです。
EFを使い始めた最初の頃、私は同じようなことをしてよく間違えました。というかいまだによく間違えます。Where句のなかでC#の関数を使ったりしてエラーのたびに「なんでや~~!?」と悩んでます。
7行目をコメントアウトし、代わりに6行目を有効にすると動作します。
または次のコードは動作します。
private void OnGet()
{
using(ApexContext db = new ApexContext())
{
var legends = db.ApexLegends.ToList();
var legendsHasShield = legends.where((x => HasShieldInPassiveAbility(x.PassiveAbility));
}
}
private bool HasShieldInPassiveAbility(string ability)
{
return ability.Contains("Shield");
}
5行目で一度Listに変換してますから、これはC#のコードとなっているからです。
ただしこれがとんでもない量のデータを掴みかねないことになります。上の例だとApexのキャラを想定していますから5行目のlegendsはせいぜい16個のデータです。16個からさらにパッシブスキルに「Shield」をもっているキャラを絞り込んでいます。
ところがApexのレジェンドがどんどん増えて、100キャラ1,000キャラ10,000キャラ…となっていけば?
仮に10,000種類のキャラがいるときにパッシブスキルに「Shield」を持っているキャラが5人いるとすると、
- 最初に全キャラのデータを取得してListにする。
- そのListからパッシブスキルに「Shield」を持つキャラを絞り込む。
ということをするのがこのコードです。必要なのは5キャラ分のデータですから、1.で10,000キャラ分のデータを一旦取得するのはとてもムダな行為になります。まかり間違ってこのコードを同時に使うユーザーが多くなれば、実行するサーバーにはムダな負荷がかかることになります。
普段私が作成したりメンテナンスしているシステムは、比較的少人数で使うものですからあまりサーバー側の負荷について意識したことはありませんでした。この動画の説明を見て、気をつけないといかんなぁと改めて思いました。
Timさんの記事を参考にどうぞ
何気に見始めた動画ですが、2時間30分あるにも関わらず一気に見てしまいました。YouTubeにあるプログラミング言語の解説系の動画は面白いものがありますね。字幕も表示できるので英語の勉強にもなります。
以上読んでいただいてありがとうございました。