1

私は WebAPI + EF5 について学んでおり、それに基づいて最初のプロジェクトを作成しました。

ID、NAME、DESCRIPTION列を持つデータベースにテーブルがあります.NAME列には、NAMEがすべてのレコードに対して一意であることを保証するための制約があります。

WebAPIプロジェクト(Visual Studioでデバッグで実行)を介してデータベースに10個のエンティティをPOSTすると、10個のアイテムが物理データベースに表示されます-クールです。

webAPI コントローラーで GET を呼び出して dbset.Local を調べると、POST した 10 個のアイテムが表示されます。これは完璧です。

問題は、Visual Studio で WebAPI プロジェクトを停止し、SQL Management Studio で DB を開き、物理行 (上記で投稿した 10 項目を表す) を削除してから、Visual Studio で WebAPI のデバッグを再開することです。(フィドラーを介して) GET 要求を実行し、コントローラーの get メソッドのブレークポイントを介して dbset を検査すると、基になるアイテムが存在しないにもかかわらず、10 個のアイテムがまだ dbset.Local プロパティにあることがわかります。 DB。GET が効果的に dbset.ToList() を呼び出して完了すると、空の結果セットが得られます。

その後、同じ 10 個のアイテムを再投稿すると、10 個のアイテムが再び DB に正常に到達しますが、dbset.Local のローカル コレクションには 20 個のアイテムが含まれています!?

WebAPI プロジェクトを再起動した後、dbset.Local が空でないのはなぜですか? デバッグを停止してコーヒーを飲み、デバッグを再開すると、dbset.Local コレクションにはまだ 20 個のアイテムが含まれています。これは私が遭遇しているキャッシングの問題ですか? Visual Studio でプロジェクトが再起動されるたびにこれを処理して dbset.Local をクリアするために、プロジェクトの起動コードで何かする必要がありますか?

また、dbset.Local が DB に設定された一意の名前の制約を尊重せず、dbset.Local コレクションへの重複エントリを許可しないのはなぜですか?エラーをスローしないでください。

4

1 に答える 1

1

問題は、Visual Studio で WebAPI プロジェクトを停止すると...

ASP.NET 内で WebAPI をホストしている場合 (Visual Studio の標準 WebAPI プロジェクトは、このようなプロジェクト タイプを作成します)、デバッガーを停止しても、アプリケーションを実行しているプロセスは実際には停止しませんが、そのアプリケーションからデバッガーを切り離すだけです。実行中のプロセスは、たとえば IIS Express を開発テスト サーバーとして使用している場合、Web サーバーのワーカー プロセスであり、存続します。(通常、Windows 画面の右下隅にあるシステム トレイに小さなアイコンがあります。そこでプロセスを停止すると、プロセスは「実際に」強制終了されます。)

... SQL 管理スタジオで DB を開き、物理行を削除します (上記で投稿した 10 項目を表します) ...

DbSet<T>.Localメモリ内のコレクションです。EF コンテキスト外の別のプロセス (SSMS) でデータベースから行を削除したことは「わかりません」。

...その後、ビジュアル スタジオで webAPI のデバッグを再開します。

上記のワーカー プロセスがまだ実行されている場合、デバッガーを再起動しても新しいプロセスは開始されませんが、デバッガーは既存のプロセスにアタッチされます。このプロセスのすべてがまだそこにあります。

(フィドラーを介して) GET 要求を実行し、コントローラーの get メソッドのブレークポイントを介して dbset を検査すると、基になるアイテムが存在しないにもかかわらず、10 個のアイテムがまだ dbset.Local プロパティにあることがわかります。 DB。

検査、反復DbSet<T>.Local、または呼び出しDbSet<T>.Local.ToList()はデータベース クエリを実行しないため、DB テーブルが空であることは認識されません。メモリ内の古いデータを返すだけです。

GET が効果的に dbset.ToList() を呼び出して完了すると、空の結果セットが得られます。

DbSet<T>.ToList()実際にデータベースクエリを実行するため、テーブルが空であることがわかり、その結果が返されます。

その後、同じ 10 個のアイテムを再投稿すると、10 個のアイテムが再び DB に正常に到達しますが、dbset.Local のローカル コレクションには 20 個のアイテムが含まれています!?

DbSet<T>.Local古い結果がまだメモリに残っていたからです。データベースへの以前のクエリは、正しいクエリ結果を提供するために空のリストを返しましたが、コレクションDbSet<T>.ToList()がクリアされたことを意味するわけではありません。Localデータベース内に (新しいキー値を持つ) 新しいエンティティが見つかった場合、このエンティティはLocalコレクションに追加されます (11 項目を表示)。ただし、クエリによって からアイテムが削除されることはありませんLocal

WebAPI プロジェクトを再起動した後、dbset.Local が空でないのはなぜですか? デバッグを停止してコーヒーを飲み、デバッグを再開すると、dbset.Local コレクションにはまだ 20 個のアイテムが含まれています。

コーヒーを 10 杯試してみてください :) 非アクティブ状態が長時間続くと、ワーカー プロセスが自動的にシャットダウンする場合があります。どれくらいの時間がかかるのか、IIS Express で発生するのかどうかはわかりません。

これは私が遭遇しているキャッシングの問題ですか? Visual Studio でプロジェクトが再起動されるたびにこれを処理して dbset.Local をクリアするために、プロジェクトの起動コードで何かする必要がありますか?

はい、Localコレクションにキャッシュされたこれらのエンティティは、複数の Web 要求で同じコンテキスト インスタンスを再利用していることを示しているため、(潜在的に) 非常に大きな問題です。これは、依存している場合Localや、他の多くの問題や例外 (たとえば、既に にあるエンティティのような同じキーを持つエンティティをアタッチする場合Localなど) に間違った結果をもたらす可能性があります。一般に、Web リクエストの開始時に新しいコンテキスト インスタンスを作成し、この単一のリクエストの処理中にそれを使用し、リクエストの終了時に破棄することがベスト プラクティスであり、推奨されます。コンテキストを破棄すると、ガベージ コレクションのためにオブジェクトが解放されます。のLocal新しいコンテキスト インスタンスのコレクションは、次のリクエストで空になります。(これとその方法(コントローラーごと、手動、依存性注入など)は、それ自体が特別な主題です。「リクエストごとのエンティティフレームワークコンテキスト」または同様のキーワードをグーグルで検索して始めてください。)

また、dbset.Local が DB に設定された一意の名前の制約を尊重せず、dbset.Local コレクションへの重複エントリを許可しないのはなぜですか?エラーをスローしないでください。

Entity Framework は一意の制約をサポートしていません (主キーの一意性を除く)。つまり、データベース内の一意のインデックスについて何も知らないだけです。

于 2013-05-31T23:19:00.483 に答える