2012-08-08 64 views
0

我一直在使用實體框架和SQL Server 3.5開發一些單用戶桌面應用程序。我以爲我曾經在某處讀過一次記錄在EF緩存中的一個上下文,如果使用不同的上下文刪除它們,即使執行新的查詢,也不會從第一個上下文的緩存中刪除它們。因此,我一直在編寫非常低效且令人迷惑的代碼,所以無論何時其他方法使用自己的上下文修改數據庫,我都可以處理上下文並實例化一個新上下文。EF緩存對SQL Server CE 3.5的工作方式不同嗎?

我最近發現了一些代碼,我沒有在這些條件下重新實例化第一個上下文,但它仍然有效。我寫了一個簡單的測試方法,看看發生了什麼事情:

 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(); 

在最後一行我很驚訝地發現,添加和刪除實體實際上通過在第二查詢返回設置斷點第一個上下文!

我幾種可能的解釋:

  1. 我在我的理解完全錯誤的,該緩存的記錄 不會在再次查詢刪除。
  2. EF在高速緩存中反覆無常,這是一個運氣問題。
  3. EF 4.1中的緩存已更改。
  4. 如果在同一進程中實例化兩個上下文,則不會出現此問題。
  5. 緩存對SQL CE 3.5的工作方式與其他版本的SQL 服務器不同。

我懷疑答案可能是最後兩個選項之一。如果我不這樣做,我真的寧願不必處理所有的麻煩,爲單用戶桌面應用程序不斷重新實例化上下文。

我可以依賴這種爲使用SQL CE(3.5和4)的單用戶桌面應用程序發現的行爲嗎?

回答

0

當您在ObjectSet上運行第二個查詢時,它將重新查詢數據庫,這就是爲什麼它反映了第二個上下文所暴露的更改。在我們深入研究這個問題之前,你確定你想要解釋2個上下文嗎?上下文應該是短暫的,所以如果你在內存中緩存你的列表或者做一些其他的事情可能會更好。

也就是說,您可以通過致電ObjectStateManager.GetObjectStateEntries並查看該商店的內容來訪問本地商店。但是,您可能要查找的是在EF 4.2及更高版本中由DbSets提供的.Local存儲。有關詳細信息,請參閱this blog post

根據您的類名判斷,它看起來像您正在使用edmx,因此您需要對文件進行一些更改以使您的上下文從DbSet繼承到對象集。 This post可以告訴你如何

+0

馬克在他的問題分析(請參閱我的答案)基本上是正確的。將我的項目轉換爲DbContext在我的議程上。回覆。第一條評論:當然,對於ASP.Net,Silverlight或Metro應用程序以及訪問遠程/分離數據庫的應用程序,上下文應該是暫時的。但作爲一個老FoxPro程序員,我發現它不得不處理編輯分離的實體或複製的數據,然後將數據保存回數據庫,以便使用本地連接的數據庫進行適度的單用戶桌面應用程序。在這種情況下,對象數據模型的功能和清晰度會被不必要的複雜代碼所稀釋。 – 2012-08-08 11:16:06

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的意思是「查詢模型而不是數據庫」。據我所知,在前面的例子中,我正在查詢數據庫。在這種情況下,我正在查詢模型。在之前的情況下查詢數據庫恰好是我想要的,而在後一種情況下,查詢模型不會產生預期的效果。 (這與我的理解顯然是一個問題,而不是與朱莉婭的建議。)