60

私はEntity Frameworkが初めてです。

EF を使用して、データベース内のいくつかの値を取得しました。完全に返され、値がラベルに表示されます。しかし、(EF を使用せずに) テーブル内のすべての値を削除すると、EF クエリは古い値を返します。EF が値をキャッシュに保存し、その後の実行のためにキャッシュされたデータを返すことはわかっています。これは正しいです?

データベース内のすべての値を削除したのに、EF が古い値を返す場合、どうすれば問題を解決できますか?

編集

今私は使用しdatamodel.SaveChanges()ました。しかし、今も同じ古い値を返しています。

私のサンプルクエリは以下のようになります:

SchoolBriefcaseEntities datamodel = new SchoolBriefcaseEntities();
datamodel.SaveChanges();
List<Compliance> compliance=new List<Compliance>();
IList<ComplianceModel> complianceModel;
if (HttpContext.Current.User.IsInRole("SuperAdmin"))
{
    compliance = datamodel.Compliances.Where(c => c.School.DistrictId == districtId).ToList();
}
4

12 に答える 12

42

変更が EF の外部で発生したことがわかっていて、特定のエンティティの ctxt を更新したい場合は、ObjectContext.Refreshを呼び出すことができます。

datamodel.Refresh(RefreshMode.StoreWins, orders);

これがよくあると思われる場合は、クエリでオブジェクト キャッシングを無効にする必要があります。

SchoolBriefcaseEntities datamodel = new SchoolBriefcaseEntities();
datamodel.tblCities.MergeOption = MergeOption.NoTracking; 

または、特定のエンティティのオブジェクト レベルのキャッシングをオフにするには、

Context.Set<Compliances>().AsNoTracking();
于 2015-05-11T14:29:09.913 に答える
31

EF を使用すると、既定で各エンティティがコンテキストごとに 1 回だけ読み込まれます。最初のクエリは、エンティティ インスタンスを作成し、内部に保存します。同じキーを持つエンティティを必要とする後続のクエリは、この格納されたインスタンスを返します。データ ストアの値が変更された場合でも、最初のクエリからの値を含むエンティティを受け取ります。

慎重な答え:

https://stackoverflow.com/a/3653392/1863179

于 2013-05-25T14:55:57.703 に答える
20

コンテキストを再クエリしない限り、EF は変更をロードしません。EF は db にクエリを実行し、それらをオブジェクトにマップしてロードします。データベースではなく、オブジェクトに対して実行された変更を監視します。EF はデータベースに直接加えられた変更を追跡せず、決して追跡しません。

リストをロードしました。そのリストはメモリ内のキャッシュです。Save Changes を呼び出しても更新されません。コンテキストをもう一度クエリする必要があります。つまり、新しいリストを作成します。

変更を確認するには、次の行をもう一度実行する必要があります。

datamodel.Compliances.Where(c => c.School.DistrictId == districtId).ToList()
于 2013-04-05T08:33:39.287 に答える
9

ここで他の解決策のいくつかに従うべきだと思いますが、キャッシュをクリアしたいようです。これは、次の手順で実現できます。

var count = datamodel.Compliances.Local.Count; // number of items in cache (ex. 30)

datamodel.Compliances.Local.ToList().ForEach(c => {
    datamodel.Entry(c).State = EntityState.Detached;
});

count = datamodel.Compliances.Local.Count; // 0
于 2015-05-14T15:13:06.500 に答える
5

次のように、コンテキストを作成した後、すべての EntitySet に MergeOption を使用することをお勧めします。

var objSetProps = ctx.GetType().GetProperties().Where(prop => prop.PropertyType.IsGenericType && prop.PropertyType.GetGenericTypeDefinition() == typeof(ObjectSet<>));
foreach (PropertyInfo objSetProp in objSetProps)
{
    ObjectQuery objSet = (ObjectQuery)objSetProp.GetValue(ctx, BindingFlags.GetProperty, null, null, null);
    objSet.MergeOption = MergeOption.PreserveChanges;
}

ここで MergeOption について読んでください: http://msdn.microsoft.com/en-us/library/system.data.objects.mergeoption.aspx NoTracking を使用すると思います。

「キャッシュされた」エンティティをクリアしたい場合は、デタッチします。

var entidades = Ctx.ObjectStateManager.GetObjectStateEntries(EntityState.Added | EntityState.Deleted | EntityState.Modified | EntityState.Unchanged);
foreach (var objectStateEntry in entidades)
    Ctx.Detach(objectStateEntry.Entity);

Ctx は私のコンテキストです。

于 2014-04-02T17:30:46.690 に答える
4

以下のコードは、オブジェクトを新しいデータベース値で更新するのに役立ちました。Entry(object).Reload() コマンドは、オブジェクトに強制的にデータベース値をリコールさせます

GM_MEMBERS member = DatabaseObjectContext.GM_MEMBERS.FirstOrDefault(p => p.Username == username && p.ApplicationName == this.ApplicationName);
DatabaseObjectContext.Entry(member).Reload();
于 2014-03-13T00:11:56.607 に答える
2

必要なのはGetDatabaseValues(). 次のように使用されます。

context.Entry(/*your entry*/).GetDatabaseValues();

以下の情報はmsdnからのものです:

現在の値は、エンティティのプロパティに現在含まれている値です。元の値は、エンティティがクエリされたときにデータベースから読み取られた値です。データベース値は、現在データベースに格納されている値です。データベース値の取得は、別のユーザーがデータベースに対して同時編集を行った場合など、エンティティがクエリされてからデータベースの値が変更された可能性がある場合に役立ちます。

于 2015-05-14T12:18:23.287 に答える
1

あなたができることをいくつか。

  1. 新しいコンテキストを使用します。キャッシュされたエンティティはコンテキストに格納されます。新しいコンテキストを使用すると、キャッシュを使用できなくなります。
  2. グローバルで永続的なコンテキストが本当に必要な場合は、2 つのサブオプションがあります。a.) 常に Reload メソッドを呼び出します。db.Entry(entity).Reload() ... これにより、コンテキストがそのエンティティを強制的にリロードします。b.) SqlDependency オブジェクトを使用して、レコードがいつ変更されたかを検出し、必要に応じてエンティティを再読み込みします。 https://code.msdn.microsoft.com/How-to-use-SqlDependency-5c0da0b3
于 2015-05-12T20:10:34.443 に答える