C# Entity Framework Core トラッキング vs NoTracking 完全比較ガイド
生徒
「C#でデータベースからデータを取り出すとき、トラッキングとかNoTrackingという言葉を聞いたのですが、これは何ですか?」
先生
「それはEntity Framework Core(EF Core)の大切な仕組みですね。簡単に言うと、取り出したデータをシステムが見守り続けるか、放っておくかの違いですよ。」
生徒
「見守るのと放っておくのでは、どんな違いが出るんですか?」
先生
「動きの速さや、データの書き換えやすさが変わります。初心者の方にもわかりやすく解説しますね!」
1. データベースとC#をつなぐEntity Framework Coreの基本
C#でアプリを作るとき、ユーザーの名前や商品の価格などの大切な情報はデータベースという場所に保存します。しかし、C#のプログラムから直接データベースを操作するのは、専門的な言葉(SQLといいます)をたくさん覚えなければならず、初心者には少し大変です。
そこで登場するのがEntity Framework Core(EF Core)です。これは、データベースとC#の仲立ちをしてくれる便利な道具です。EF Coreを使うと、まるで普通のリストや変数を扱うような感覚でデータベースを操作できます。この便利な道具の中で、特に重要なのがトラッキングという機能です。
トラッキングとは、日本語で追跡という意味です。データベースから取り出してきたデータが、今どんな状態にあるのかをEF Coreが常に監視している状態を指します。これを理解することが、効率的なアプリ開発の第一歩になります。
2. トラッキング(追跡あり)とは何か?
トラッキングが有効な状態を、日常の例えで考えてみましょう。あなたは図書館の司書さんだとします。利用者が本を借りに来ました。トラッキングとは、誰がどの本を借りていったかを名簿にしっかり記録し、返ってくるまで見守っている状態です。
もし利用者が本に落書きをして返してきたら、司書さんは名簿を見て、どの本が変わったのかすぐに気づくことができます。これと同じことがプログラムでも起きています。
EF Coreでトラッキングが有効な場合、データベースから取り出したデータがプログラムの中で書き換えられると、EF Coreがそれを自動的に検知します。そして、最後に保存ボタンを押すだけで、変更された内容をデータベースに反映してくれるのです。初心者がまず覚えるべきは、この変更を自動で見つけてくれる仕組みです。
using (var context = new MyDbContext())
{
// データベースからIDが1のユーザーを取得(トラッキングあり)
var user = context.Users.FirstOrDefault(u => u.Id == 1);
// 名前の書き換え
user.Name = "新しい名前";
// SaveChangesを呼ぶだけで、自動的にUPDATE文が実行される
context.SaveChanges();
}
3. AsNoTracking(追跡なし)とは何か?
次に、トラッキングを行わないAsNoTrackingについて解説します。これは、先ほどの図書館の例で言うなら、本をコピーして渡すだけで、後は一切関知しない状態です。
利用者がそのコピーに何を書いても、司書さんは気にしません。名簿にも記録しません。このように、データを読み込むだけで、後で変更する予定がない場合に使うのがNoTrackingです。追跡しない分、司書さんの手間(パソコンの計算量)が減り、非常にスピーディーに動作します。
主に、Webサイトで記事の一覧を表示したり、ランキングを表示したりするなど、画面に出すだけで変更はしないという場面で大活躍します。
using (var context = new MyDbContext())
{
// データを表示するだけなら、追跡をオフにする
var products = context.Products
.AsNoTracking()
.ToList();
foreach (var p in products)
{
Console.WriteLine(p.Name);
}
}
4. トラッキングとNoTrackingの決定的な違い
この二つの大きな違いは、メモリの節約と処理速度、そして更新のしやすさにあります。トラッキングありの状態では、EF Coreはデータのコピーを内部に保持し続けます。これにより、元のデータと今のデータを比較して変更を見つけることができますが、その分だけパソコンのメモリを消費します。
一方、NoTrackingを使うと、この比較用のコピーを作成しません。そのため、大量のデータを一度に読み込むときは劇的に処理が速くなります。プログラミングにおいて、無駄な計算を省くことは非常に重要です。
また、トラッキングありの場合は、データベースから取り出した情報を少し変えて保存するだけで済みますが、NoTrackingの場合は、変更を保存しようとしてもEF Coreがデータのことを忘れているため、そのままでは保存できません。別途、これは自分が知っているデータですよと教え直す作業が必要になります。
5. どのような場面で使い分けるべきか?
初心者の方が迷わないための判断基準はとてもシンプルです。まずは以下のルールを覚えておきましょう。
- データを更新・削除したいとき:通常のトラッキングあり(デフォルトの状態)を使います。
- データを画面に表示するだけ、あるいは計算に使うだけのとき:AsNoTrackingを使います。
例えば、スマホアプリの設定画面で自分のプロフィールを編集するときはトラッキングが必要です。名前を変えて保存ボタンを押すからです。逆に、ニュースアプリで今日のニュースを100件読み込むときは、ニュースの内容をその場で書き換えることはないので、NoTrackingが最適です。このように、目的が参照なのか更新なのかを考えることが、良いプログラムを書くコツです。
6. 具体的なコードで比較してみよう
実際に、NoTrackingを使ってデータを読み込んだ後に、無理やり更新しようとするとどうなるかを見てみましょう。この違いを知っておくことで、エラーが起きたときに対処しやすくなります。
using (var context = new MyDbContext())
{
// 追跡なしでデータを取得
var book = context.Books.AsNoTracking().First();
book.Title = "タイトル変更";
// 追跡していないので、SaveChangesを呼んでも何も起きない
context.SaveChanges();
Console.WriteLine("保存されました(実際にはデータベースは変わっていません)");
}
上記のコードでは、タイトルを書き換えて保存処理をしていますが、実際にはデータベースの中身は変わりません。なぜなら、EF Coreがこの本のデータを追跡対象リストに入れていないからです。このように、NoTrackingを使う際は注意が必要ですが、正しく使えばアプリをとても軽くすることができます。
7. パフォーマンスを意識した高度なテクニック
プログラミングに少し慣れてきたら、パフォーマンス(動作の快適さ)をさらに意識してみましょう。実は、EF Coreには、コンテキスト全体でデフォルトの設定をNoTrackingにする方法もあります。
多くのアプリケーションでは、データの更新よりも読み取りの方が圧倒的に多いです。そのため、基本は追跡しない設定にしておき、更新が必要な場所だけ個別に追跡を有効にするという設計手法もあります。これにより、うっかり追跡を忘れてメモリを無駄遣いすることを防げます。
// 全体で追跡をオフにする設定例
context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
// この状態だと、普通に検索しても追跡されない
var logs = context.SystemLogs.ToList();
ただし、この設定を使う場合は、今自分がどちらの状態を扱っているのかを常に把握しておく必要があります。初心者のうちは、一つ一つのクエリ(命令)に対して、必要に応じてAsNoTrackingを付け足していくスタイルが、ミスが少なくておすすめです。
8. データの状態(EntityState)を理解しよう
少し難しい言葉ですが、EntityState(エンティティ・ステート)というものについても触れておきます。これはデータの状態を指す言葉です。トラッキングされているデータは、未変更(Unchanged)、変更あり(Modified)、追加(Added)、削除(Deleted)といったラベルが貼られます。
EF Coreはこのラベルを見て、最後にどのような命令をデータベースに送るかを決めています。NoTrackingの場合は、このラベルが貼られず、常にデタッチャブル(分離された)という状態になります。パソコンに詳しい人がよく使う用語ですが、要するに管理外ということです。このラベルの仕組みがあるからこそ、私たちは複雑な命令を書かずに済んでいるのです。
9. 初心者がハマりやすい注意点
最後に、よくある失敗例を紹介します。それは、一つの処理の中でトラッキングありのデータと、NoTrackingのデータを混ぜてしまうことです。特に、複数のデータを組み合わせて新しいデータを作るときに、片方の追跡が外れていると、思いもよらないエラーが出ることがあります。
また、IDを使ってデータを検索するとき、トラッキングありだと一度取得したデータはメモリからすぐに返してくれますが、NoTrackingだと毎回データベースに聞きに行ってしまいます。これを使い分けることで、ネットワークの負荷もコントロールできるようになります。
難しく感じるかもしれませんが、まずは「変更するならトラッキング、見るだけならNoTracking」という原則を大切にしてください。それだけで、あなたの書くプログラムは格段にプロっぽくなります。