我现在正在学习EF,关于对象上下文(ObjectContext)有一个问题:
当我访问数据库时,每个查询(函数)都应该创建ObjectContext的实例吗?
还是最好只创建一次(单例)并重复使用它?
在使用EF之前,我使用企业库数据访问块,并为DataAccess函数创建了一个数据访问实例...
我现在正在学习EF,关于对象上下文(ObjectContext)有一个问题:
当我访问数据库时,每个查询(函数)都应该创建ObjectContext的实例吗?
还是最好只创建一次(单例)并重复使用它?
在使用EF之前,我使用企业库数据访问块,并为DataAccess函数创建了一个数据访问实例...
我认为最常见的方法是按请求使用它。在开始时创建它,进行所需操作(大多数情况下这些操作需要通用ObjectContext),在结束时释放它。大多数DI框架都支持此场景,但您还可以使用HttpModule
创建上下文并将其放置在HttpContext.Current.Items
中。这是一个简单的示例:
public class MyEntitiesHttpModule : IHttpModule
{
public void Init(HttpApplication application)
{
application.BeginRequest += ApplicationBeginRequest;
application.EndRequest += ApplicationEndRequest;
}
private void ApplicationEndRequest(object sender, EventArgs e)
{
if (HttpContext.Current.Items[@"MyEntities"] != null)
((MyEntities)HttpContext.Current.Items[@"MyEntities"]).Dispose();
}
private static void ApplicationBeginRequest(Object source, EventArgs e)
{
var context = new MyEntities();
HttpContext.Current.Items[@"MyEntities"] = context;
}
}
对于每个查询都需要使用它。ObjectContext是一个轻量级对象,因此每次需要时创建一个ObjectContext的成本不高。
此外,您保持ObjectContext存活的时间越长,它包含的缓存对象就越多,因为您针对它运行查询。这可能会导致内存问题。因此,将ObjectContext作为单例模式是一个特别糟糕的想法。随着您的应用程序的使用,您会在单例ObjectContext中加载越来越多的实体,直到最终您将整个数据库加载到内存中(除非您在不再需要它们时分离实体)。
然后还有一个可维护性问题。有一天,您试图跟踪错误,但无法确定导致它的数据是从哪里加载的。
就像Luke所说,这个问题在SO上已经被问了很多次。
对于Web应用程序来说,每个请求周期似乎是最好的选择。单例绝对是一个坏主意。
每个请求都可以很好地工作,因为一个Web页面有一个用户,可能有一些属于该用户的项目,可能有一些该用户的消息。您希望使用相同的ObjectContext,以便您可以转到User.Messages来获取它们,也许将一些消息标记为已读,也许添加一个项目,然后在页面周期完成时提交或放弃整个对象图。
public class DBModel {
private const string _PREFIX = "ObjectContext";
// DBModel.GetInstance<EntityObject>();
public static ObjectContext GetInstance<T>() {
var key = CreateKey<T>();
HttpContext.Current.Items[key] = HttpContext.Current.Items[key] ?? Activator.CreateInstance<T>();
return HttpContext.Current.Items[key] as ObjectContext;
}
private static string CreateKey<T>() {
return string.Format("{0}_{1}", _PREFIX, typeof(T).Name);
}
}