0

我一直在使用 Entity Framework 和 SQL Server 3.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();

在最后一行设置断点我惊讶地发现添加和删除的实体实际上并没有被第一个上下文的第二个查询返回!

我有几种可能的解释:

  1. 我完全错误地理解,缓存记录在重新查询时不会被删除。
  2. EF 在缓存方面反复无常,这是一个运气问题。
  3. EF 4.1 中的缓存已更改。
  4. 当两个上下文在同一进程中实例化时,不会出现此问题。
  5. SQL CE 3.5 的缓存工作方式与其他版本的 SQL Server 不同。

我怀疑答案可能是最后两个选项之一。如果我不必这样做,我真的宁愿不必处理不断为单用户桌面应用程序重新实例化上下文的所有麻烦。

对于使用 SQL CE(3.5 和 4)的单用户桌面应用程序,我可以依赖这种发现的行为吗?

4

2 回答 2

0

当您在 ObjectSet 上运行第二个查询时,它正在重新查询数据库,这就是为什么它反映了您的第二个上下文所公开的更改。在我们深入讨论之前,您确定要像您解释的那样拥有 2 个上下文吗?上下文应该是短暂的,因此如果您将列表缓存在内存中或做其他类似的事情可能会更好。

话虽如此,您可以通过调用ObjectStateManager.GetObjectStateEntries并查看那里的商店来访问本地商店。但是,您可能正在寻找的是 .Local 存储,它由 EF 4.2 及更高版本中的 DbSets 提供。有关这方面的更多信息,请参阅此博客文章。

从您的类名来看,您似乎正在使用 edmx,因此您需要对文件进行一些更改,以使您的上下文从 DbSet 继承到对象集。 这篇文章可以告诉你如何

于 2012-08-08T01:56:25.323 回答
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 回答