C# 实体框架的这种实现是否会泄漏内存?
当在web应用程序或控制台应用程序的using语句中使用实体上下文时,我就是搞不清楚它是否在使用流中被释放 谢谢C# 实体框架的这种实现是否会泄漏内存?,c#,entity-framework-4,memory-leaks,idisposable,disposable,C#,Entity Framework 4,Memory Leaks,Idisposable,Disposable,当在web应用程序或控制台应用程序的using语句中使用实体上下文时,我就是搞不清楚它是否在使用流中被释放 谢谢 using System; using System.Web; namespace Foo.Model { public partial class FooEntities : ObjectContext { private const string CurrentContextKey = "FooEntities.Current";
using System;
using System.Web;
namespace Foo.Model
{
public partial class FooEntities : ObjectContext
{
private const string CurrentContextKey = "FooEntities.Current";
[ThreadStatic]
private static FooEntities _currentOnThreadStatic;
private FooEntities _previousContext;
/// <summary>
/// Gets the current <see cref="FooEntities"/> instance, if an instance can be shared in the current context.
/// </summary>
/// <remarks>
/// The current context is stored in the HTTP context, if it is available (otherwise it is stored in a thread-static instance).
/// Multiple contexts can be stacked.
/// </remarks>
public static FooEntities Current
{
get
{
if (HttpContext.Current != null)
{
return HttpContext.Current.Items[CurrentContextKey] as FooEntities;
}
else
{
return _currentOnThreadStatic;
}
}
private set
{
if (HttpContext.Current != null)
{
HttpContext.Current.Items[CurrentContextKey] = value;
}
else
{
_currentOnThreadStatic = value;
}
}
}
/// <summary>
/// Returns a repository instance bound to this object context.
/// </summary>
/// <typeparam name="TRepository">The type of repository to instantiate.</typeparam>
/// <returns>The repository instance.</returns>
public TRepository GetRepository<TRepository>()
where TRepository: BaseRepository
{
return (TRepository) Activator.CreateInstance(typeof(TRepository), this);
}
/// <summary>
/// Ensures that an ambient context is available through <see cref="Current"/>, throwing an exception otherwise.
/// </summary>
/// <exception type="InvalidOperationException)">
/// Thrown if <see cref="Current"/> is null.
/// </exception>
public static void EnsureContext()
{
if (Current == null)
{
throw new InvalidOperationException("An ambient FooEntities context is expected.");
}
}
/// <summary>
/// Releases the context instance.
/// </summary>
/// <param name="disposing"></param>
protected override void Dispose(bool disposing)
{
Current = _previousContext;
base.Dispose(disposing);
}
/// <summary>
/// Is called by all constructors.
/// </summary>
partial void OnContextCreated()
{
_previousContext = Current;
Current = this;
}
}
}
使用系统;
使用System.Web;
名称空间Foo.Model
{
公共部分类实体:ObjectContext
{
private const string CurrentContextKey=“FooEntities.Current”;
[线程静态]
私有静态实体\u currentOnThreadStatic;
私人实体(前文),;
///
///获取当前实例(如果实例可以在当前上下文中共享)。
///
///
///如果当前上下文可用,则将其存储在HTTP上下文中(否则将存储在线程静态实例中)。
///可以堆叠多个上下文。
///
公共静态实体当前
{
得到
{
if(HttpContext.Current!=null)
{
返回HttpContext.Current.Items[CurrentContextKey]作为FooEntities;
}
其他的
{
返回_currentOnThreadStatic;
}
}
专用设备
{
if(HttpContext.Current!=null)
{
HttpContext.Current.Items[CurrentContextKey]=值;
}
其他的
{
_currentOnThreadStatic=值;
}
}
}
///
///返回绑定到此对象上下文的存储库实例。
///
///要实例化的存储库的类型。
///存储库实例。
公共存储库GetRepository()
存放地点:BaseRepository
{
return(TRepository)Activator.CreateInstance(typeof(TRepository),this);
}
///
///确保环境上下文通过可用,否则将引发异常。
///
///
///如果为空,则抛出。
///
公共静态文本()
{
如果(当前==null)
{
抛出新的InvalidOperationException(“应为环境FooEntities上下文”);
}
}
///
///释放上下文实例。
///
///
受保护的覆盖无效处置(布尔处置)
{
当前=_先前的上下文;
基地。处置(处置);
}
///
///由所有构造函数调用。
///
部分无效OnContextCreated()
{
_previousContext=当前;
电流=这个;
}
}
}
这是一种奇怪的设计。正如@joelc在他的评论中指出的,您应该将对象上下文视为一个短暂的对象,在需要时创建它,然后立即释放
但我看不出这会泄露内存的原因。您只处理托管资源,并且始终使用相同的密钥访问
HttpContext
,因此不会创建新对象。您有理由尝试在HttpContext中存储ObjectContext吗?上下文被认为是轻量级的,通常在需要时创建实例,然后处理掉它。因此,foodentities.Current可以用于在不同的类中插入实例,这样就不必在构造函数中注入实例,并在所有这些类中保持相同的实例。我认为您应该阅读这篇文章:这可能会促使您重新考虑线程静态上下文。@Ladislav Mrnka:我认为实现id是c*&p。我不支持它,也没有写它,也没有想象它。我认为实体上下文应该被注入到需要访问模型的类中,顶级请求处理程序应该实例化它。太难看了!总之,我同意你的观点,希望没有人把它作为做什么的例子,而是作为不做什么的例子。ObjectContext是IDisposable的,所以它不是托管资源。这就是我担心内存泄漏的原因。@Four:对不起,之前没有看到OnContextCreated
,但我仍然认为这很好,因为保持链接列表活动的“锚”是HttpContext
,它本身非常短暂。它更像一个内存“气球”,而不是内存泄漏。所有的东西最终都会被释放,所以从技术上讲这不是一个漏洞。但是,在最终处置之前加载到上下文中的实体越多,用于更改跟踪、跟踪关系等的内存就越多。@Anders实际上,终结器确保释放托管资源。如果您使用的是非托管资源,如句柄,您自己负责,如果不正确处理对象,将导致内存泄漏。但是,它最常用于托管资源,以确保及时处理事务,而不是等待GC,例如数据库连接。@Joel:如果遵循实现IDiposable
的普通模式,终结器将调用Dispose(false)
,这将释放所有非托管资源。false
标志告诉Dispose(bool disposing)
它应该忽略任何托管引用,只释放非托管资源。