はじめに
こんにちは。
最近私はAIにコードの書き方について意見を求めたりすることがよくあるのですが、
それを通じて小さな気付きを得たので記事にして書いてみようと思います。
SingleAsyncというのがある・・・
NRではEntity Framework Core や LINQ を使って開発しているんですが、そのコードの一部をAIに見せて改善点がないか訊いてみました。
すると「この場面ではFirstAsync ではなく SingleAsync を使った方がいい」と言われたんです。。。。
「1個取りたい=FirstAsyncだ!!!!」と思っていた私は、その見覚えのないSingleAsyncを見て驚きました。
「…SingleAsyncってなに???」
ちゃんと調べた
FirstAsyncとSingleAsync、名前や意味はなんとなく似ていますが、意味・責務はまったく違うんですね。。。
結論(先に)
| メソッド | 想定件数 | 0件 | 複数件 |
|---|---|---|---|
| FirstAsync | 1件以上 | 例外 | OK |
| SingleAsync | ちょうど1件 | 例外 | 例外 |
- FirstAsync = 「どれか1件取れればいい」
- SingleAsync = 「1件でなければおかしい」
※両方にOrDefaultメソッドがあり、nullを許容する以外の違いは同じ
FirstAsync とは
var item = await query.FirstAsync();
挙動
- 条件に合う 最初の1件 を返す
- 条件に合うものが複数件あっても問題なし
- 0件の場合は例外になる
意味
「1件以上存在する前提で、その中の先頭を取る」
並び順が意味を持つケースと相性が良いです。
SingleAsync とは
var user = await users.SingleAsync(x => x.Id == id);
挙動
- 必ず1件だけ存在することを要求する
- 0件 → 例外
- 2件以上 → 例外
意味
「この条件で複数存在したら設計ミス」
SingleAsync は 取得 というより、この条件で1件しか存在しないことを期待するメソッド。
設計観点での使い分け(重要)
SingleAsync を使うべきケース
- PK / Unique Index 検索
- Aggregate Root の取得
- 「複数あったら即バグ」でいい処理
await query.SingleAsync(x => x.Id == id);
FirstAsync を使うべきケース
- 並び順に意味がある
- UI 用の表示データ
- 「代表1件」が欲しいだけ
await query.Where(x => x.IsDefault).FirstAsync();
つまり、私はIdなどで絞り込みをして必ず1件しかヒットしなさそうなところでFirstAsyncを書いていたので、AIに「SingleAsync」をお勧めされたのでした。。。。
DBのUnique制約あるのにSingleAsyncいるの…??
ここまで調べて私は、「…でもDBにUnique制約かけてるけど…????」と思いました。
つまり、SingleAsyncが「必ず1件である」ということを保証してくれるってことだけど、DBでUnique制約かけてるんだからもうそれでいいじゃない、と思ったわけです。
もちろん、それも1つの正解です。
しかし、一方でそれでもSingleAsyncを使いたい人もいるわけで。
じゃぁ何がこれを二分するのかというと、設計の思想だとか、パフォーマンスなどの観点なんですよね。
| 論点 | Single派 | First派 |
|---|---|---|
| 設計意図 | 明確 | やや弱い |
| 異常検知 | 強い | 弱い |
| パフォーマンス | やや不利 | 有利 |
| 可読性 | 「一意前提」が伝わる | シンプル |
Singleは「必ず1件である」を強くコードに反映するために設計意図が明確で異常検知にも強い。
一方でFirstの方が「当てはまるものを1件見つけたら終了」となるため処理が軽いです。
※ただし、通常の業務システムではUnique Index が効いていれば、実際の性能差はそこまでではないと思われる。。
「コードから設計意図が読めるようにしたい」という人は「必ず1件である」ということをコード上で明示するために、SingleAsyncを使うとよさそう。
コードはシンプルにしたいし、とにかく早さを求めていきたいという人はFirstAsyncの方がいいという考えもありそうですね。
まとめ
FirstAsyncしか知らないところに、ひょんなことからSingleAsyncを知ったわけですが、そこには設計思想が深く関係していることがわかりました。
これをまた開発に生かしていけたらなと思います。