0

私は、EntityFrameworkとSQLServer3.5を使用していくつかのシングルユーザーデスクトップアプリを開発してきました。あるコンテキストのEFキャッシュにレコードが入ると、別のコンテキストを使用してレコードが削除されると、新しいクエリが実行されても、最初のコンテキストのキャッシュからレコードが削除されないことをどこかで読んだと思います。したがって、私は本当に非効率的でわかりにくいコードを書いているので、別のメソッドが独自のコンテキストを使用してデータベースを変更するたびに、コンテキストを破棄して新しいコードをインスタンス化できます。

最近、これらの条件下で最初のコンテキストを再インスタンス化していないコードを発見しましたが、とにかく機能しました。何が起こっているのかを確認するための簡単なテストメソッドを作成しました。

        using (UnitsDefinitionEntities context1 = new UnitsDefinitionEntities())
        {
            List<RealmDef> rdl1 = (from RealmDef rd in context1.RealmDefs
                                   select rd).ToList();
            RealmDef rd1 = RealmDef.CreateRealmDef(100, "TestRealm1", MeasurementSystem.Unknown, 0);
            context1.RealmDefs.AddObject(rd1);
            context1.SaveChanges();
            int rd1ID = rd1.RealmID;

            using (UnitsDefinitionEntities context2
                = new UnitsDefinitionEntities())
            {
                RealmDef rd2 = (from RealmDef r in context2.RealmDefs
                                where r.RealmID == rd1ID select r).Single();
                context2.RealmDefs.DeleteObject(rd2);
                context2.SaveChanges();
                rd2 = null;
            }

            rdl1 = (from RealmDef rd in context1.RealmDefs select rd).ToList();

最後の行にブレークポイントを設定すると、追加および削除されたエンティティが、最初のコンテキストの2番目のクエリによって実際に返されないことに驚きました。

私はいくつかの可能な説明:

  1. キャッシュされたレコードが再クエリ時に削除されないという私の理解は完全に間違っています。
  2. EFはキャッシングに気まぐれで、運の問題です。
  3. キャッシングはEF4.1で変更されました。
  4. この問題は、2つのコンテキストが同じプロセスでインスタンス化された場合には発生しません。
  5. SQL CE 3.5のキャッシュは、他のバージョンのSQLサーバーとは動作が異なります。

答えは最後の2つの選択肢の1つかもしれないと思います。必要がなければ、シングルユーザーデスクトップアプリのコンテキストを絶えず再インスタンス化する際のすべての面倒に対処する必要はありません。

SQL CE(3.5および4)を使用するシングルユーザーデスクトップアプリでこの検出された動作を信頼できますか?

4

2 に答える 2

0

どうやら説明#1の方が事実に近かったようです。例の最後に次のステートメントを挿入します。

var cached = context1.ObjectStateManager.GetObjectStateEntries(System.Data.EntityState.Unchanged);

レコードが実際にはまだキャッシュにあることが明らかになりました。上記の例でデータベースが実際に再クエリされるという点で、Mark Oreta は基本的に正しかった。

ただし、ナビゲーション プロパティの動作は明らかに異なります。たとえば、次のようになります。

        RealmDef distance = (from RealmDef rd in context1.RealmDefs
                             where rd.Name == "Distance"
                             select rd).Single();
        SystemDef metric = (from SystemDef sd in context1.SystemDefs
                            where sd.Name == "Metric"
                            select sd).Single();
        RealmSystem rs1 = (from RealmSystem rs in distance.RealmSystems
                           where rs.SystemID == metric.SystemID
                           select rs).Single();

        UnitDef ud1 = UnitDef.CreateUnitDef(distance.RealmID, metric.SystemID, 100, "testunit");
        rs1.UnitDefs.Add(ud1);
        context1.SaveChanges();

        using (UnitsDefinitionEntities context2 = new UnitsDefinitionEntities())
        {
            UnitDef ud2 = (from UnitDef ud in context2.UnitDefs
                           where ud.Name == "testunit"
                           select ud).Single();
            context2.UnitDefs.DeleteObject(ud2);
            context2.SaveChanges();
        }

        udList = (from UnitDef ud in rs1.UnitDefs select ud).ToList();

この場合、最後のステートメントの後で中断すると、最後のクエリがキャッシュから削除されたエントリを返すことがわかります。これが私の混乱の元でした。

Julia Lerman が「データベースではなく、モデルをクエリする」という言葉の意味をよりよく理解できたと思います。私が理解しているように、前の例ではデータベースにクエリを実行していました。この場合、私はモデルを照会しています。前の状況でデータベースにクエリを実行すると、意図したとおりに実行されましたが、後者の状況では、モデルにクエリを実行しても望ましい効果が得られませんでした。(これは明らかに私の理解の問題であり、Julia のアドバイスではありません。)

于 2012-08-08T10:50:51.523 に答える
0

ObjectSet で 2 番目のクエリを実行すると、データベースが再クエリされるため、2 番目のコンテキストによって公開された変更が反映されます。これについて詳しく説明する前に、説明しているような 2 つのコンテキストが必要ですか? コンテキストは短命である必要があるため、リストをメモリにキャッシュするか、そのような性質の何かを行う場合は、より良いかもしれません。

そうは言っても、そこにあるものを呼び出して表示することで、ローカルストアにアクセスできますObjectStateManager.GetObjectStateEntries。ただし、おそらく探しているのは、EF 4.2 以降の DbSet によって提供される .Local ストレージです。詳細については、このブログ投稿を参照してください。

クラス名から判断すると、edmx を使用しているように見えるため、コンテキストが DbSet からオブジェクトセットに継承されるようにするには、ファイルにいくつかの変更を加える必要があります。 この投稿では、その方法を説明できます

于 2012-08-08T01:56:25.323 に答える