我的问题
我有一个用于测试并发性的简单 WebForms 项目。
我在用:
1. Entity Framework 4.3.1 code first approach.
2. DevExpress ASP.net controls to visualize my data. Specifically an ASPXGridView control.
3. MySQL as database backend.
现在我遇到了并发检查的问题。
即使我是唯一一个编辑数据的用户,如果我使用 DevExpress ASPXGridView 两次编辑相同的记录,我也会遇到并发异常!
我得到的例外是: System.Data.OptimisticConcurrencyException
我的设置
** 为简洁起见,此处进行了简化
我的代码优先实体定义如下:
public class Country
{
//Some constructors here
[Required, ConcurrencyCheck]
public virtual string LastUpdate { get; set; }
[Required, Key, DatabaseGenerated(DatabaseGeneratedOption.None)]
public virtual int CountryID { get; set; }
//Various other data fields here
}
您可以看到我添加了一个名为 LastUpdate 的字段,由于设置了 [ConcurrencyCheck] 属性,正在测试并发检查。
在我的带有 DevExpress ASPXGridView 的网页上,我使用 EntityDataSource 在网格视图和实体框架之间进行绑定。网格视图正在使用弹出编辑器。我有以下事件:
protected void Page_Load(object sender, EventArgs e)
{
//Hook entity datasource to grid view
dbgCountries.DataSource = CountriesEntityDataSource;
dbgCountries.DataBind();
}
protected void CountriesEntityDataSource_ContextCreating(object sender, EntityDataSourceContextCreatingEventArgs e)
{
//Create and hook my DBContext class to the entity
//datasources ObjectContext property.
var context = new MyDBContextClass();
e.Context = ((IObjectContextAdapter)context ).ObjectContext;
}
protected void dbgCountries_InitNewRow(object sender, DevExpress.Web.Data.ASPxDataInitNewRowEventArgs e)
{
//I create a new MyDBContextClass here and use it
//to get the next free id for the new record
}
protected void dbgCountries_CustomErrorText(object sender, DevExpress.Web.ASPxGridView.ASPxGridViewCustomErrorTextEventArgs e)
{
//My code to catch the System.Data.OptimisticConcurrencyException
//excpetion is in here.
//I try to rtefresh the entity here to get the latest data from
//database but I get an exception saying the entity is not being
//tracked
}
protected void dbgCountries_RowValidating(object sender, DevExpress.Web.Data.ASPxDataValidationEventArgs e)
{
//Basic validation of record update in here
}
protected void dbgCountries_RowUpdating(object sender, DevExpress.Web.Data.ASPxDataUpdatingEventArgs e)
{
//I set the LastUpdate field (my concurrency field)
//to the current time here
}
我还连接了一些按钮事件来测试直接并发测试。
例如
- Get Entity
- Update Entity
- Update DB directly with sql
- Save Entity
- Get concurrency exception as expected
例如
- Get Entity
- Update Entity
- Save Entity
- No issue.
- Get Entity again.
- Update Entity again.
- Save Entity again.
- No issue.
这些按钮按预期工作。只有网格更新似乎有问题。
也许是因为网格需要使用 ObjectContect 而我的实体框架类使用的是 DBContext?
我尝试的修复
我搜索了互联网试图找到解决方案。检查了 DevExpress 论坛,检查了 StackOverflow 上的其他帖子,互联网上的各种帖子,关于并发的 Microsoft MSDN 文章,我就是无法解决这个问题。
没有一个帖子像我的那样“简单”。他们都涉及其他数据。例如主/细节relashionship。自定义编辑器。等等我正在使用所有内置的 DevExpress 控件,只在我的数据库表/实体上显示一个网格视图。
一些帖子建议刷新实体。我试过这个,但得到一个异常,说实体没有在对象状态管理器中被跟踪。
我尝试通过销毁和重新创建我的对象上下文/数据库上下文来刷新实体框架,但不知何故我仍然遇到并发问题。
我尝试使用 DBContext 和 ObjectContext 进行刷新。都没有奏效。(objContext.Refresh(RefreshMode.StoreWins,实体)。我要么得到一个异常,如前所述]实体没有被跟踪,或者如果我告诉它只刷新未修改的实体,那么什么都不会发生(没有刷新,没有例外)
我尝试将我的 DBContext 设为全局,但这并不好,因为 WebForms 似乎想要在每次 Web 刷新后重新创建其整个状态并重新挂钩其网格数据上下文等。(页面加载,用户点击编辑,用户点击确定更新)
现在所有这些解决方案似乎都考虑了在并发异常之后要做什么。看到我什至不应该首先得到例外,我想他们不会有帮助。
建议
你们中有人对如何进行这项工作有任何建议吗?
从网格发布数据后,我是否必须强制实体框架手动刷新?(我现在才想到这个)
我的设置似乎很简单。也许我错过了一些非常明显的东西。我还没有过多地使用 WebForms 或 EntityFramework,所以我可能缺少一些简单(而且可能很明显)的解决方案?
任何帮助表示赞赏。
谢谢彼得梅斯