我一直在学习WebAPI + EF5,并基于此创建了我的第一个项目。
我在数据库中有一个表,其中包含ID,NAME,DESCRIPTION列,NAME列上有一个约束,以确保NAME对所有记录都是唯一的。
当我POST通过WebAPI项目(在Visual Studio中的调试中运行)向数据库说十个实体时,十个项目出现在物理数据库中 - 很酷。
如果我在webAPI控制器上调用GET,并检查dbset.Local,我会看到我发布的10个项目,这是完美的。
问题是,如果我在visual studio中停止WebAPI项目,在SQL管理工作室中打开数据库并删除物理行(代表我上面发布的10个项目),然后在visual studio中重新启动webAPI的调试。如果我执行GET请求(通过fiddler)并通过contoler的get方法中的断点检查dbset,我发现10个项目仍然在dbset.Local属性中,即使底层没有项目D B。如果我允许GET有效地完成调用dbset.ToList(),我得到一个空的结果集。
如果我重新发布相同的10个项目,则10个项目再次成功到达数据库,但现在dbset.Local在其本地集合中有20个项目!?
重新启动WebAPI项目后,为什么dbset.Local不为空,我可以停止调试去咖啡重启调试和dbset.Local集合中还有20个项目吗?这是我遇到的缓存问题吗?我在项目启动代码中需要做些什么,每次在Visual Studio中重新启动项目时都要处理这个以清除dbset.Local?
为什么dbset.Local不遵守在DB中设置的唯一名称的约束,并允许重复的条目进入dbset.Local集合,如果它没有抛出错误?
答案 0 :(得分:1)
问题是如果我在visual studio中停止WebAPI项目......
如果您在ASP.NET中托管了WebAPI(Visual Studio中的标准WebAPI项目将创建这样的项目类型),则停止调试器实际上不会停止正在运行您的应用程序的进程,但它只会分离来自该应用程序的调试器。正在运行的进程是 - 例如,如果您使用IIS Express作为开发测试服务器 - Web服务器的工作进程,它将保持活动状态。 (它通常在Windows屏幕右下角的系统托盘中有一个小图标。您可以在那里停止该过程,然后该过程“真正”被杀死。)
...在SQL管理工作室中打开数据库并删除物理行 (代表我在上面发布的10个项目)......
DbSet<T>.Local
是内存中的集合。它没有“看到”您在EF上下文之外的另一个进程(SSMS)中删除了数据库中的行。
...然后在visual studio中重新启动webAPI的调试。
如果提到的工作进程仍在运行,则重新启动调试器将无法启动新进程,但将调试器附加到现有进程。这个过程中的一切仍然存在。
如果我执行GET请求(通过fiddler)并通过中断检查dbset 指向contoler的get方法,我发现有10个项目 仍然在dbset.Local属性中,即使没有项目 在基础数据库中。
因为检查或迭代DbSet<T>.Local
或调用DbSet<T>.Local.ToList()
没有运行数据库查询,所以它不会注意到DB表是空的。它只返回内存中的旧数据。
如果我允许GET有效地调用dbset.ToList()我 得到一个空的结果集。
由于DbSet<T>.ToList()
实际上 运行数据库查询,因此会发现该表为空并将结果返回给您。
如果我重新发布相同的10个项目,则10个项目成功到达 再次使用DB,但现在dbset.Local在其Local中有20个项目 集合!?
因为DbSet<T>.Local
仍然在内存中有旧的结果。虽然您之前对数据库的DbSet<T>.ToList()
查询返回了一个空列表以提供正确的查询结果,但这并不意味着它清除了Local
集合。如果它在数据库中找到了一个新实体(具有新的键值),则该实体将被添加到Local
集合中(然后显示11个项目)。但查询永远不会从Local
中删除项目。
重新启动WebAPI项目后,为什么dbset.Local不为空,我 可以停止调试去咖啡重启调试和 dbset.Local集合中还有20个项目吗?
尝试10次咖啡:)工作人员进程可能会在较长时间不活动后自动关闭。我不确定它需要多长时间以及它是否会在IIS Express中发生。
这是我遇到的缓存问题吗?有什么我需要的 在我的项目启动代码中,要处理这个以清除dbset.Local 每次在visual studio中重新启动项目?
是的,它(可能)是一个非常大的问题,因为Local
集合中缓存的那些实体表明您正在多个Web请求中重用相同的上下文实例。当您依赖Local
以及许多其他问题和异常时(例如,当您附加具有相同键的实体(如已在Local
中的实体等)时,这可能会导致错误的结果。) 。这通常是最佳实践,建议在Web请求开始时创建新的上下文实例,在处理此单个请求期间使用它,然后在请求结束时将其处理。处置上下文将释放对象以进行垃圾回收。下一个请求时,新上下文实例的Local
个集合将为空。 (这个以及怎么做(每个控制器,手动,依赖注入等)本身就是一个特殊的主题。尝试谷歌搜索“每个请求的实体框架上下文”或类似的关键字开始。)
为什么dbset.Local不遵守唯一名称的约束 在DB中设置并允许重复条目进入dbset.Local 收集,它不应该抛出错误吗?
实体框架不支持唯一约束(主键的唯一性除外),即它只是对数据库中的唯一索引一无所知。