EntityFramework SaveChanges() 抛出并发事务错误

EntityFramework SaveChanges() throws concurrent transaction error

在我的 MVC 应用程序中,我有一个页面从我的 POLICIES table 加载一条记录,然后在我的视图中使用它。然后我的视图在页面上显示该记录的数据,但是为了编辑记录数据,用户需要单击 "Edit Policy" 按钮,这将启动一个 jQuery UI 对话框编辑模式下的相同记录。我意识到我可以只允许他们从主视图对其进行编辑,但这不是我的客户想要的。

我遇到的问题是,当我在 jQuery UI 对话框中时,当我尝试保存记录时出现以下错误。

FirebirdSql.Data.FirebirdClient.FbException: lock conflict on no wait transaction

我的对话框的控制器方法执行以下代码。 PolicyModel 只是一个 class,用作对话框的 ViewModel,而 Policy 属性 是表示 Policy table.

的对象
public ActionResult Policy(int policyNo) {
     PolicyModel policyModel = new PolicyModel();
     policyModel.Policy = dbContext.POLICIES.FirstOrDefault(db => db.POLICY_NO == policyNo);
     return View(policyModel);
}

在 "Policy" 视图中,我使用以下方法创建标准表单:

@using (Html.BeingForm("SavePolicy", "MyController", FormMethod.Post)) {
    //hidden element for policyNo created with @Html.HiddenFor
    //form elements here created using the @Html.TextBoxFor..etc.
}

要保存的对话框按钮只是使用 var formData = new FormData($('#myformid').get(0)); 创建新的 FormData,然后我将其传递给我的保存控制器方法。

保存方法设置如下

public ActionResult SavePolicy(PolicyModel policyModel) {

     var policy = dbContext.POLICIES.FirstOrDefault(db => db.POLICY_NO == policyModel.POLICY_NO);

     if (TryUpdateModel(policy,"Policy", updateFields.ToArray())) {
         dbContext.Entry(policy).State = EntityState.Modified;
         dbContext.SaveChanges();
     }

     return Json( new { result = 1, JsonRequestBehavior.AllowGet } );

}

如果我手动将 POLICY_NO 更改为任何其他策略编号,而不是像这样在对话框中当前处于活动状态的编号...

var policy = dbContext.POLICIES.FirstOrDefault(db => db.POLICY_NO == 12345);

存档将正确更新。

这就像对话框视图持有资源或其他东西。有什么想法吗?

更新

作为参考,dbContext 的范围限定为控制器 class,我的 SavePolicy 方法位于其中,如下所示...

public class MainController : Controller {
     private DBModel dbContext = new DBModel();

     // other methods

     public ActionResult SavePolicy(PolicyModel policyModel) {

          // method code as see above

     }

}

ASP.NET MVC 控制器通常有这个:

protected override void Dispose(bool disposing)
{
    if (disposing)
    {
        db.Dispose();
    }
    base.Dispose(disposing);
}

因此,如果您要在操作之外声明上下文,则应验证是否已实现此方法。

事实证明,在第一次执行时 (a select),您的上下文 keeps track of the record at Firebird and it is never disposed。第二次执行将再次尝试 select 相同的条目,该条目仍被另一个未正确处理的上下文跟踪。

在每个动作中使用范围上下文是另一种解决方法,但在我看来它有点麻烦。