每个请求缓存Entity Framework DbContexts

5
我有几个基于System.Entity.Data.DbContext的类。它们在Web应用程序的不同端点中多次使用,实例化它们是否会很昂贵?
我曾经将它们的副本缓存在HttpContext.Current.Items中,因为每个请求中有多个它们的副本感觉不太对劲,但我现在发现它不会自动从HttpContext中释放。在我编写代码(在Application_EndRequest中)来处理它之前,我想重新审视这种情况,因为如果我只需要在需要它们的地方实例化并在那里处理它们,那么缓存它们就没有意义。
类似于此类问题已经在互联网上提出过,但我似乎找不到一个确切回答我的问题的问题。如果我重复了别人的问题,我很抱歉。
更新
我已经发现在this博客文章中处理上下文的销毁可能并不重要,但我仍然想知道它们在首次实例化时是否很昂贵。基本上,EF幕后是否有很多魔法需要避免频繁执行?

另一个SO答案基本上回答了我的问题:这里。为了加快创建速度,可以根据这个问题使用缓存的EntityConnection(尽管需要注意它不是线程安全的)。我还不能回答自己的问题,所以我会等待看看是否有其他候选人。 - sjmeverett
可能是每个Web请求一个DbContext...为什么?的重复问题。 - Steven
4个回答

6

最好使用一个IoC容器来管理生命周期--它们非常擅长此项任务,这是相当常见的情况。这样做的额外好处是使动态调用变得容易--意味着对您的样式表的请求不会创建DB上下文,因为它在BeginRequest()中被硬编码。


你有特别推荐的吗? - sjmeverett
如果没有任何限制,我可能会选择StructureMap,因为我比较熟悉它。大多数(如果不是全部)“命名”容器都具备此功能。 - Wyatt Barnett

4

为了完整起见,我自己回答一下这个问题。

这篇答案提供了更多关于这个问题的信息。

总之,实例化DbContext并不是很昂贵,所以不用担心。

此外,您真的不需要担心处理数据上下文。您可能会注意到,在他的示例中,ScottGu通常将上下文作为控制器上的私有字段(field)。这篇答案提供了Linq to SQL团队关于处理数据上下文的一些好信息,而这篇博客文章也深入探讨了这个主题。


3

使用HttpContext.Items并在EndRequest手动处理您的上下文 - 甚至可以为此创建自定义HTTP模块。这是正确的处理方式。上下文处理还将释放对所有跟踪实体的引用,并允许GC收集它们。

如果您确实需要多个上下文,则可以在请求中使用多个上下文,但在大多数情况下,一个上下文就足够了。如果您的服务器处理是一个逻辑操作,则应为整个工作单元使用一个上下文。如果您在事务中进行更多更改,那么使用多个上下文会导致事务升级为分布式,并且会产生负面的性能影响。


谢谢。我不太明白“您的交易将被升级为分布式”的含义,能否请您澄清一下?但是您是否需要释放上下文呢?更新问题中提到的博客文章似乎表明不用释放,而且我注意到Scott Gu经常使用私有字段作为上下文,这样就不需要进行释放了。 - sjmeverett
@Ladislav的观点对我们非常重要。我们依赖于事务范围内的多个上下文,这当然会导致通过DTC促进事务。然而,我们仍然发现实体集被有效地清理,不需要强制上下文进行处理。我知道这不是“高效”的编程或“最佳实践”,但它确实“有效”。当我们强制处理上下文时,还有一个奇怪的副作用,即使用异步时应该是独立实例的相同上下文实例会出错。 - Smudge202

0

我们有一个Web项目,使用了与您描述的类似模式(尽管使用多个独立的L2S上下文而不是EF)。虽然上下文在请求结束时没有被处理,但我们发现由于HttpContext.Current变得无法引用,GC会在适当的时候收集上下文,在幕后进行处理。我们使用内存分析器确认了这一点。虽然上下文的持久化时间比应该长一些,但对我们来说是可以接受的。

自从注意到这种行为以来,我们已经尝试了几种替代方案,包括在EndRequest上处理上下文,并在EndRequest上强制进行GC Collect(那不是我的想法,很快就被撤回了)。

我们现在正在调查在请求期间涵盖我们上下文集合的工作单元模式的实现可能性。如果您在谷歌上搜索,会发现一些很棒的文章,但对我们来说,实施所需的时间超过了潜在的好处。

此外,我现在正在调查将其移动到组合SOA /工作单元方法的复杂性,但再次,这是一种事后诸葛亮的感觉,因为在没有知识的情况下构建了一个企业级应用程序。

我很想听听其他人对这个主题的看法。


谢谢。我已经想到让GC在某个时候处理它并不适用于重负载,最好是确定性的,但我会首先承认我对那个领域不太了解。我不会使用GC.Collect,参见答案以获得更好的解决方案。你认为缓存上下文值得吗? - sjmeverett
我认为有一条非常模糊的界限。由于我们应用程序的结构,除了将上下文实现为存储在HttpContext中的工厂的单例模式之外,任何其他模式都会给我们带来噩梦 - 必须确保实体加载到相关上下文中,确保在使用延迟加载属性时未处理上下文。我们确实遇到了一个“事件”,在每个请求期间生成了大约比所需多15个上下文,可能类似于不缓存上下文。结果导致了显着的性能损失。 - Smudge202
这是一篇我刚刚偶然发现的有趣文章,它可能适用于你。我认为同样适用于EF上下文 - 基本上,SQL连接将会被关闭,所以不必担心处理上下文。 - sjmeverett
我之前没有看到那篇文章,所以感谢你提供链接。还有一件事值得注意的是,当我提到GC在“适当的时候”处理上下文时,分析器显示它们几乎立即在请求完成后被丢弃 - 特别是在返回大量结果集时。但我找不到这种行为存在的原因 - 我最初的想法是请求完成后自动进行gen1收集,但这并不完全正确。这绝对是需要运行一些性能监控来确定什么最适合你的情况。祝好运! - Smudge202

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接