我想在会话中共享一个 dbcontext。我了解使用共享的缓存 Dbcontexts 存在许多问题。
所以我创建了一个全局 dbcontext 并将其保存在一个静态类变量中。
我能够创建选择、创建新实体、通过调用后面的代码中的 dbcontext 进行插入和更新,而不会出现问题
出于并发原因,我想在我的 web 表单中的 entitydatasource 控件中使用相同的 dbcontext。我通过使用 OnContextCreating 和 ONContextdisposing 事件来做到这一点。这适用于读取数据,但是当我尝试通过实体数据源(来自数据视图、网格视图等)进行更新时,出现以下异常
AcceptChanges cannot continue because the object's key values conflict with
another object in the ObjectStateManager. Make sure that the key values are unique
before calling AcceptChanges.
我已将产生错误的系统减少为 ef5.0 数据模型,使用单个表和具有单个实体数据源的单个 Web 表单页面。我已经复制了下面的代码
public partial class _Default : Page
{
static QuantumDataEntities dbcontext = null;
protected void Page_Load(object sender, EventArgs e)
{
}
protected void OnContextCreating(object sender, EntityDataSourceContextCreatingEventArgs e)
{
if (dbcontext == null)
dbcontext = new QuantumDataEntities();
e.Context = (dbcontext as IObjectContextAdapter).ObjectContext;
}
protected void OnContextDisposing(object sender, EntityDataSourceContextDisposingEventArgs e)
{
e.Cancel = true;
}
}
如您所见,它非常简单。每当 Entitydatasource 需要一个对象上下文来读取、更新等时,它都会调用 OnContextCreating。我在第一个 OnContextCreating 调用中创建 dbcontext,缓存在静态类变量中并为将来的 OnContextCreating 调用重用。OnContextCreating 事件被调用了几次,首先是页面加载,接下来是按下编辑按钮时的回发,最后(我认为)是实际的 dbsave。
如果我得到缓存并为每个调用创建一个新的 dbcontext,它就可以正常工作。即替换
if (dbcontext == null)
dbcontext = new QuantumDataEntities();
e.Context = (dbcontext as IObjectContextAdapter).ObjectContext;
和
dbcontext = new QuantumDataEntities();
e.Context = (dbcontext as IObjectContextAdapter).ObjectContext;
此错误还有其他一些奇怪之处。如果我设置了一个 OnUpdating 事件,它应该在 entitydataosource 执行任何更新之前被调用,它永远不会被调用。我已经包含了异常的堆栈跟踪和本文的结尾。
我想用 EF 6.0 Alpha 3 对此进行测试,但设计人员已将对象上下文移动到另一个程序集中,使其与 entitydatasouce 不兼容
这是我们网站进一步发展的主要障碍。我们现在唯一的选择是移动到非共享的 dbcontext,这将导致极端的性能问题(即在页面加载时多次加载相同的 20K 数据集 - 是的,我们可以重新架构,我们将需要数周时间/个月,我们现在没有)
问题 ?
- 到底是怎么回事 ?
- 难道我做错了什么 ?(相对于糟糕的架构)
异常堆栈跟踪
[InvalidOperationException: AcceptChanges cannot continue because the object's key values conflict with another object in the ObjectStateManager. Make sure that the key values are unique before calling AcceptChanges.]
System.Data.Objects.ObjectStateManager.FixupKey(EntityEntry entry) +2518309
System.Data.Objects.EntityEntry.AcceptChanges() +159
System.Data.Objects.ObjectContext.AcceptAllChanges() +356
System.Web.UI.WebControls.EntityDataSourceView.ExecuteUpdate(IDictionary keys, IDictionary values, IDictionary oldValues) +376
System.Web.UI.DataSourceView.Update(IDictionary keys, IDictionary values, IDictionary oldValues, DataSourceViewOperationCallback callback) +87
System.Web.UI.WebControls.DetailsView.HandleUpdate(String commandArg, Boolean causesValidation) +1091
System.Web.UI.WebControls.DetailsView.HandleEvent(EventArgs e, Boolean causesValidation, String validationGroup) +425
System.Web.UI.WebControls.DetailsView.OnBubbleEvent(Object source, EventArgs e) +89
System.Web.UI.Control.RaiseBubbleEvent(Object source, EventArgs args) +37
System.Web.UI.WebControls.DetailsViewRow.OnBubbleEvent(Object source, EventArgs e) +80
System.Web.UI.Control.RaiseBubbleEvent(Object source, EventArgs args) +37
System.Web.UI.WebControls.LinkButton.OnCommand(CommandEventArgs e) +121
System.Web.UI.WebControls.LinkButton.RaisePostBackEvent(String eventArgument) +156
System.Web.UI.WebControls.LinkButton.System.Web.UI.IPostBackEventHandler.RaisePostBackEvent(String eventArgument) +10
System.Web.UI.Page.RaisePostBackEvent(IPostBackEventHandler sourceControl, String eventArgument) +13
System.Web.UI.Page.RaisePostBackEvent(NameValueCollection postData) +9642898
System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +1724