Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

EntityFramework SaveChanges() throws concurrent transaction error

In my MVC application, I have a page that loads a record from my POLICIES table and then uses it in my View. My View then has the data from this record displayed on the page, however in order to edit the record data the user needs to click the "Edit Policy" button, which launches a jQuery UI dialog with the same record in EDIT mode. I realize I could just allow them to edit it from the main View, however that is not what my client wants.

The trouble I'm having is, when I'm in my jQuery UI Dialog, I get the error below when I try to save the record.

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

The Controller method for my dialog executes the following code. The PolicyModel is simply a class which serves as the ViewModel for the dialog, and the Policy property is an object representing the Policy table.

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

In the "Policy" View, I do a standard form using:

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

The dialog button to save simply creates new FormData with var formData = new FormData($('#myformid').get(0)); I then pass that to my save controller method.

The Save method is set up like the following

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 } );

}

If I change the POLICY_NO manually though to ANY other policy number than the one currently active in the dialog like this...

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

The save will update correctly.

It's like the dialog View is holding onto the resource or something. any ideas?

UPDATE

For reference, the dbContext is scoped to the Controller class in which my SavePolicy method lives as seen below...

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

     // other methods

     public ActionResult SavePolicy(PolicyModel policyModel) {

          // method code as see above

     }

}
like image 918
Phil Avatar asked Dec 03 '25 04:12

Phil


1 Answers

ASP.NET MVC Controllers usually have this:

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

So, if you are declaring your context outside of your action, you should verify if this method is implemented.

Turns out that, at the first execution (a select), your context keeps track of the record at Firebird and it is never disposed. The second execution will try to select the same entry again, which is still tracked by another context that was not disposed properly.

Using the scoped context inside each action is another way to solve, but it is a bit more cumbersome in my standpoint.

like image 99
Leonel Sanches da Silva Avatar answered Dec 05 '25 20:12

Leonel Sanches da Silva