modest violet

modest violet

開発者としてのあれこれや、日々の雑記など

your future hasn't written yet. no one's has.
by Emmett Lathrop "Doc" Brown

EntityFramework初心者が陥りやすいコンカレンシーエラーの原因と対策

Entity Framework(EF)は、.NETフレームワーク上で動作するオブジェクト関連マッピング(ORM)フレームワークです。これは、データベースとの対話をより簡単にし、データベースの操作をオブジェクト指向のアプローチで行うことを可能にします。初心者がEntity Frameworkを使用する際によく遭遇する問題の一つが、「トラッキング」に関連するものです。コンカレンシーエラー(競合エラー)が発生して「何で!?」となるケースが多いです。

ラッキング(追跡)とは

Entity Frameworkのトラッキングは、データベースから取得したエンティティ(データベースの行に対応するオブジェクト)が変更されたかどうかを把握するメカニズムです。これにより、変更が検出された場合に、データベースに対して変更を反映させることができます。

コンカレンシーエラーとは

コンカレンシーエラーは、複数のユーザーまたはプロセスが同じデータを同時に変更し、競合が発生した場合に発生するエラーです。例えば、ユーザーAが特定のエンティティを取得し、その後ユーザーBが同じエンティティを取得して変更を加え、ユーザーAが変更を保存しようとすると、競合が発生してコンカレンシーエラーが発生する可能性があります。

ラッキングとコンカレンシーエラーの関連

Entity Frameworkでは、トラッキングが有効な場合、データベースから取得したエンティティは変更が追跡されます。そして、データベースの更新が行われる際に、更新前にエンティティが変更されていないかを確認します。しかし、これが同時に複数のユーザーで行われる場合、競合が発生しやすくなります。

コンカレンシーエラーの種類

  1. Optimistic Concurrency(楽観的同時実行制御): これは、競合が発生する可能性があるが、実際に発生するまで待つのではなく、変更が競合しないことを期待する手法です。これは、Entity Frameworkではデフォルトのアプローチであり、トラッキングが有効な場合に適用されます。

  2. Pessimistic Concurrency(悲観的同時実行制御): これは、変更が競合する可能性がある場合、変更の間にロックをかける手法です。しかし、これは性能の低下やデッドロックの危険性があるため、通常は避けられます。

解決策

初心者が経験する典型的な失敗は、トラッキングがデータベースの更新に影響を与えることです。例えば、以下のような状況が考えられます:

  1. データを取得し、オブジェクトを変更する。
  2. データベースに保存(更新)するが、変更が反映されない。

これは、EFがデフォルトでトラッキングを有効にしているためです。対策としては、次の2つの方法があります。

1. 明示的にAsNoTrackingを指定する

var entity = dbContext.Entities.AsNoTracking().FirstOrDefault(e => e.Id == 1);

AsNoTrackingメソッドを使用すると、取得したエンティティがトラッキングされず、変更がデータベースに影響を与えなくなります。ただし、この場合、変更をデータベースに保存するためには、明示的にオブジェクトを追跡する必要があります。

2. UseQueryTrackingBehaviorを使用して規定値を変更する

dbContext.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;

QueryTrackingBehaviorを使用して、デフォルトのクエリトラッキングの挙動を変更できます。例えば、NoTrackingを指定すると、全てのクエリがデフォルトでトラッキングを無効にします。

まとめ

Entity Frameworkのトラッキングは、変更をデータベースに反映させる重要な概念ですが、仕組みを理解しないと意図しない挙動が発生することがあります。AsNoTrackingQueryTrackingBehaviorを理解し、適切に利用することで、これらの問題を回避できます。