2012-08-08 67 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的意思是“查询模型而不是数据库”。据我所知,在前面的例子中,我正在查询数据库。在这种情况下,我正在查询模型。在之前的情况下查询数据库恰好是我想要的,而在后一种情况下,查询模型不会产生预期的效果。 (这与我的理解显然是一个问题,而不是与朱莉娅的建议。)