おそらくDbContext
とDbSet
が行うキャッシングを誤解しているのかもしれませんが、キャッシングが続くという印象を受けました。次のコードを実行したときに予期しない動作が見られます。
var ctx = CreateAContext();
var sampleEntityId = ctx.SampleEntities.Select(i => i.Id)
.Single(i => i == 3); //Calls DB as expected
var cachedEntityId = ctx.SampleEntities.Select(i => i.Id)
.Single(i => i == 3); //Calls DB unexpectedly
何が起きてる? DbSet
から得られるものの一部は、データベースを照会する前にそのオブジェクトが存在するかどうかを最初にローカルキャッシュで確認することだと思いました。ここに欠けている設定オプションのようなものはありますか?
@ emcas88が言おうとしている は、DbSet
で.Find
メソッドを使用した場合にのみEFがキャッシュをチェックすることです。
.Single
、.First
、.Where
などを使用しても、2次キャッシュを使用していない限り、結果はキャッシュされません。
これは、extensorメソッドの実装では、コンテキストのFindメソッドを使用するためです
contextName.YourTableName.Find()
最初にキャッシュを検証します。それが役に立てば幸い。
時々私の拡張メソッドを使用します:
using System.Linq;
using System.Linq.Expressions;
namespace System.Data.Entity
{
public static class DbSetExtensions
{
public static TEntity FirstOrDefaultCache<TEntity>(this DbSet<TEntity> queryable, Expression<Func<TEntity, bool>> condition)
where TEntity : class
{
return queryable
.Local.FirstOrDefault(condition.Compile()) // find in local cache
?? queryable.FirstOrDefault(condition); // if local cache returns null check the db
}
}
}
使用法:
db.Invoices.FirstOrDefaultCache(x => x.CustomerName == "Some name");
FirstOrDefaultをSingleOrDetfaultに置き換えることもできます。
EF Docs を見てください。答えが見つかります:
DbSetとIDbSetは常にデータベースに対してクエリを作成し、返されたエンティティが既にコンテキストに存在していても、常にデータベースへのラウンドトリップを伴うことに注意してください。次の場合に、データベースに対してクエリが実行されます。
- foreach(C#)またはFor Each(Visual基本)ステートメント。
ToArray
、ToDictionary
、ToList
などのコレクション操作によって列挙されます。First
やAny
などのLINQ演算子は、クエリの最も外側の部分で指定されます。- 次のメソッドが呼び出されます:
Load
のDbSet
拡張メソッド、DbEntityEntry.Reload
、およびDatabase.ExecuteSqlCommand
。
EF6はootbをキャッシュする結果を行いません。結果をキャッシュするには、2次キャッシュを使用する必要があります。 CodePlexでこの有望なプロジェクトを参照してください。
データベースのデータが変更されても、すぐにそれを知ることはできないことに注意してください。これはプロジェクトによっては重要な場合があります。 ;)