EFキャッシュに関する質問はたくさんありますが、私の問題に対する解決策はまだ見つかりません。
Entity Framework 6キャッシュを完全に無効にするにはどうすればよいですか?または、データに何かが起こったためにキャッシュを忘れるようにプログラムでEFに伝えることはできますか?
まず、inheritedEF(エンティティを定義するためのモデル優先)とプレーンデータ(データを操作するための)の奇妙な混合物で作成されたアプリケーションがあります。私がしたことは、アプリケーションをリファクタリングして次のことをすることでした。
GetAll()
など)を作成するDbContext.Database.Connection
を使用して、SQLの複雑なデータ操作を終了しますSpring.Web
サポートを追加して、DIおよびトランザクションを有効にします(まだではありません)現時点では、アプリケーションのメイン機能(巨大なデータセットで複雑なSQLクエリを実行)が以前と同じように機能するようにコードを再編成しましたが、ルックアップドメインエンティティの操作はを使用してよりスマートに行われますできるだけ多くのEntity Framework
私が継承したページの1つは、マルチチェックボックスページです。これは、理解を深めるために表示します。壊れた機能の開発をブロックするよりも、現在の問題を修正してコードをリファクタリングする方が安価であるため、以前の実装者の選択については説明しません。
これはページがどのように見えるかです
基本的に、Controller
メソッドは次のとおりです。
[HttpPost]
public ActionResult Index(string[] codice, string[] flagpf, string[] flagpg, string[] flagammbce, string[] flagammdiv, string[] flagammest,
string[] flagintab, string[] flagfinanz, string[] flagita, string[] flagest, string pNew){
Sottogruppo2015Manager.ActivateFlagFor("pf", flagpf);
Sottogruppo2015Manager.ActivateFlagFor("pg", flagpg);
Sottogruppo2015Manager.ActivateFlagFor("ammbce", flagammbce);
Sottogruppo2015Manager.ActivateFlagFor("ammdiv", flagammdiv);
Sottogruppo2015Manager.ActivateFlagFor("ammest", flagammest);
Sottogruppo2015Manager.ActivateFlagFor("intab", flagintab);
Sottogruppo2015Manager.ActivateFlagFor("finanz", flagfinanz);
Sottogruppo2015Manager.ActivateFlagFor("ita", flagita);
Sottogruppo2015Manager.ActivateFlagFor("est", flagest);
return RedirectToAction("Index", new { pNew });
}
各string[]
パラメーターは、テーブル内の列です。 ActivateFlagFor
メソッドは、2つのクエリを順番に実行します
UPDATE table SET --param1-- = 0;
UPDATE table SET --param1-- = 1 where id in (--param2--)
動作は次のとおりです。
アプリケーションをリロードすると問題が解決するため、これはキャッシュの問題であると確信しています。アプリケーションの主な機能は完全にSQLベースであるため、ルックアップテーブルへの変更はメイン操作に反映され、これが正しい動作です。
EFキャッシングはパフォーマンスにとって優れた機能であることを理解していますが、私の場合は、少なくともアプリケーション全体をLINQ DMLに移行するまでは(おそらく不可能です)望んでいません。
DbContext
の使用方法もちろん、「DbContextをどのように使用していますか?」 「正しく処分しますか?」。
I<Entity>Manager
拡張BaseManager
ですDbContext
はリクエストスコープのSpringオブジェクトです。私はすでに リクエストスコープのオブジェクトの破棄について尋ねました ですが、現在、回避策を実装していますが、悪い一方で、正しく破棄するリクエスト。public class ExampleManagerImpl : BaseManager, IExampleManager
{
public void ActivateFlagFor(string aFlag, string[] aList)
{
string sql = "UPDATE table SET flag" + aFlag + " = 0";
RunStatementV1(sql);
if (aList != null && aList.Any())
{
sql = "UPDATE table SET flag" + aFlag + " = 1 WHERE id in (" + aList.ToCsvApex() + ")";
RunStatementV1(sql);
}
}
public IList<Models.Example> GetAll()
{
return DataContext.example.ToList(); //I don't dispose of the DataContext willingly
}
}
そして
public abstract class BaseManager {
public DbContext DataContext { get; set; } //Autowired
protected void RunStatementV1(string aSqlStatement)
{
IDbConnection connection = DataContext.Database.Connection;
if (connection.State == ConnectionState.Closed || connection.State == ConnectionState.Broken) connection.Open(); //Needed because sometimes I found the connection closed, even if I don't dispose of it
using (IDbCommand command = connection.CreateCommand())
{
command.CommandText = aSqlStatement;
command.ExecuteNonQuery();
}
}
}
Detach
は問題を解決するようですが、いつか元に戻すために、それを多数のエンティティに適用する必要があります将来はデータ取得のためにEF6のキャッシュを完全に無視したい場合は、AsNoTracking()
をクエリの最後に追加します(ToList()
を呼び出すか、クエリを実行する他の操作を行う前に)。
これを行うと、既存のデータのキャッシュをチェックしたり、データベース呼び出しの結果をキャッシュに追加したりしないことに注意してください。また、Entity Frameworkは、データベースから取得したエンティティへの変更を自動的に検出しません。エンティティを変更してデータベースに保存する場合は、SaveChanges()
を呼び出す前に、変更したエンティティを添付する必要があります。
現在の方法は次のとおりです。
public IList<Models.Example> GetAll()
{
return DataContext.example.ToList();
}
次のように変更されます。
public IList<Models.Example> GetAll()
{
return DataContext.example.AsNoTracking().ToList();
}
EFのキャッシュを処理する他のオプションに興味がある場合は、 EF6キャッシュバスティングに関するブログ投稿 を作成しました。
私もこの問題を抱えていましたが、修正できました。
リポジトリパターンを使用し、.Net CoreのデフォルトDIを使用しています。 AddSingleton(...)を使用していますが、DbContextで使用するのは間違っています。
そこで、ドキュメントから読むように、AddScopedに変更しました:スコープ付きライフタイムサービスは、リクエストごとに1回作成されます。
それは私の問題を解決しました。
ms docsからこのセクションを読む必要があります:Service Lifetimes and Registration Options