質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
Entity Framework

Entity Frameworkは、.NET Framework 3.5より追加されたデータアクセス技術。正式名称は「ADO.NET Entity Framework」です。データベースエンジンに依存しておらず、データプロバイダの変更のみで様々なデータベースに対応できます。

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

SQL Server

SQL Serverはマイクロソフトのリレーショナルデータベース管理システムです。データマイニングや多次元解析など、ビジネスインテリジェンスのための機能が備わっています。

Windows Forms

Windows Forms(WinForms)はMicrosoft .NET フレームワークに含まれる視覚的なアプリケーションのプログラミングインターフェイス(API)です。WinFormsは管理されているコードの既存のWindowsのAPIをラップすることで元のMicrosoft Windowsのインターフェイスのエレメントにアクセスすることができます。

.NET Framework

.NET Framework は、Microsoft Windowsのオペレーティングシステムのために開発されたソフトウェア開発環境/実行環境です。多くのプログラミング言語をサポートしています。

Q&A

解決済

1回答

2377閲覧

EntityFrameworkでSELECT時に、DBから取得したデータが古い

locoJr.

総合スコア15

Entity Framework

Entity Frameworkは、.NET Framework 3.5より追加されたデータアクセス技術。正式名称は「ADO.NET Entity Framework」です。データベースエンジンに依存しておらず、データプロバイダの変更のみで様々なデータベースに対応できます。

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

SQL Server

SQL Serverはマイクロソフトのリレーショナルデータベース管理システムです。データマイニングや多次元解析など、ビジネスインテリジェンスのための機能が備わっています。

Windows Forms

Windows Forms(WinForms)はMicrosoft .NET フレームワークに含まれる視覚的なアプリケーションのプログラミングインターフェイス(API)です。WinFormsは管理されているコードの既存のWindowsのAPIをラップすることで元のMicrosoft Windowsのインターフェイスのエレメントにアクセスすることができます。

.NET Framework

.NET Framework は、Microsoft Windowsのオペレーティングシステムのために開発されたソフトウェア開発環境/実行環境です。多くのプログラミング言語をサポートしています。

1グッド

0クリップ

投稿2022/08/11 12:46

編集2022/08/12 00:34

前提

EntityFramework(EF6)を使用し、DBからSELECTしDataGridViewへバインドさせています。
一定間隔で自動でSELECT~バインドを繰り返しているのですが、その間にDBのレコードの値を変更してもなぜかSELECTしたデータは変更前のままです。

DBのレコードの値変更は、SSMS(SQL Server Management Studio)で編集する機能から実施しています。
EntityFrameworkにキャッシュしたデータを都度読み出しているのかと思い、SQL Server Profilerで確認しましたが都度SELECTが実行されているようでした。

Contextのインスタンスをコンストラクタやプロパティの初期値などで生成すると古いデータがSELECTされ、バインドする直前に生成すると新しいデータがSELECTされます。
Contextはシングルトンなどで一度生成したら以後はそのまま・・・というような感じだったと記憶があったのですが、想定外の動きをして困っています。
※動き的には先にトランザクションをはってしまっているような感じ。

後者(バインドする直前にインスタンス生成)だと都度コネクション確立などが発生し処理負荷が高くなると考えており、なんとかContextは一度だけ生成して都度新しいデータをSELECTしたいです。

実現したいこと

  • Contextは一度だけ生成して都度新しいデータをSELECTしたい

該当のソースコード

cs

1//メンバ変数 2private DbContext _context = new DbContext(); 3private System.Timers.Timer _timer; 4 5//コンストラクタ 6public Frm() 7{ 8 InitializeComponent(); 9 10 _timer = new System.Timers.Timer() 11 { 12 Interval = 1000, 13 AutoReset = false, 14 SynchronizingObject = this, 15 }; 16 _timer.Elapsed += _timer_Elapsed; 17} 18 19//フォームロード 20private void Frm_Load(object sender, EventArgs e) 21{ 22 _timer.Start(); 23} 24 25 26private async void _timer_Elapsed(object sender, ElapsedEventArgs e) 27{ 28 await BindViewAsync(); 29 _timer.Start(); 30} 31 32private async Task BindViewAsync() 33{ 34 List<model.test> tests = await _context.test.Where(r => l.State == 1).ToListAsync(); 35 DataGridView1.DataSource = tests.Select(r => new { ID = r.id, 名前 = r.name }).ToList(); 36}

試したこと

EntityFramework(EF6)からEntityFrameworkCore3.1へ変更しても同じでした。

補足情報(FW/ツールのバージョンなど)

VS2022
.NET Framework 4.7.2
WinForm
EntitiFramework(EF6)
SQL Server 2019 Express
※SQL Server認証など設定していますが、他は基本的に規定値のままです。

退会済みユーザー👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

Linq to Entities でエンティティを取得する場合、デフォルトではエンティティは DbContext にキャッシュされるそうです。

以前以下のような話がありました。その話は表題とは異なり、ロールバックは期待通り動いていたがキャッシュのために動いてないと勘違いしたというものです。

トランザクションのロールバックが意図通りに動かない
https://teratail.com/questions/359867

エンティティをキャッシュする理由は、以下の Microsoft のドキュメントに書いてあるように、追跡を行うためということです。

追跡と追跡なしのクエリ
https://docs.microsoft.com/ja-jp/ef/core/querying/tracking

"追跡クエリで結果が返されると、EF Core で、エンティティが既にコンテキスト内に存在するかどうかがチェックされます。 EF Core で既存のエンティティが検出された場合は、同じインスタンスが返されます"

Contextはシングルトンなどで一度生成したら以後はそのまま

そういうことはないはずですし、今回のようなケースでは毎回生成するのが正解だと思います。

もしくは DbExtensions.AsNoTracking メソッドを適用する(追跡しないようにする)と "Returns a new query where the entities returned will not be cached in the DbContext or ObjectContext." ということで、キャッシュは使われなくなるようです。そのやり方が質問者さんのケースで正解なのかどうかは分かりませんが、試してみてはいかがですか。

投稿2022/08/11 13:38

退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

locoJr.

2022/08/11 13:57

ご回答ありがとうございます。 クエリが発行されるのはContextに対してSelectやSaveChangesなどをしたときなので、もしかしてどこでインスタンス生成しても変わらないんですかね。。。 ASP.NET CoreなどではDI注入でContextを制御していたりするようですが、ただ最初にインスタンスを生成しているだけではないのですかね~。 > もしくは DbExtensions.AsNoTracking メソッドを適用する(追跡しないようにする) コンストラクタで「_context.test.AsNoTracking();」を実行しましたが、結果は変わらずでした。。。 キャッシュを持ってきているわけではないようです。
locoJr.

2022/08/11 14:10

> > もしくは DbExtensions.AsNoTracking メソッドを適用する(追跡しないようにする) > コンストラクタで「_context.test.AsNoTracking();」を実行しましたが、結果は変わらずでした。。。 すみません、実行の仕方を間違えていました。 List<model.test> tests = await _context.test.Where(r => l.State == 1).ToListAsync();  ↓ List<model.test> tests = await _context.test.AsNoTracking().Where(r => l.State == 1).ToListAsync(); にしたら、都度インスタンス生成はいらずに最新値がSELECTできました! Contextは都度生成するのが普通のやり方なんでしょうか。
退会済みユーザー

退会済みユーザー

2022/08/11 15:05

> Contextは都度生成するのが普通のやり方なんでしょうか。 ケースバイケースと思いますが、キャッシュされるというのは事実ですので、それが問題なら (1) 都度廃棄再生成、(2) AsNoTracking、(3) Reload する他ないと思います。
locoJr.

2022/08/11 15:34

> ケースバイケースと思いますが、キャッシュされるというのは事実ですので、それが問題なら (1) 都度廃棄再生成、(2) AsNoTracking、(3) Reload する他ないと思います。 ありがとうございます。 それぞれで試してみて、一番しっくりくるものに決めたいと思います。 また、「(2) AsNoTracking」に関してはSELECT時にパフォーマンスが向上するかもしれないようでした。 https://docs.microsoft.com/ja-jp/ef/ef6/querying/no-tracking 大変助かりました、ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問