MVC 4 Optimistic concurrency exception

2019-08-28 16:20发布

问题:

Having faced this issue (I wanted to allow an edit by using a bootstrap modal window, i'm using MVC4 and entity framework), when I want to save my changes, I have this error message since I'm using the modal window :

Store update, insert, or delete statement affected an unexpected number of rows (0). Entities may have been modified or deleted since entities were loaded. Refresh ObjectStateManager entries.

Here are my actions :

[HttpGet]
        public ActionResult EditPerson(long id)
        {
            var person = db.Persons.Single(p => p.Id_Person == id);

            ViewBag.Id_ProductPackageCategory = new SelectList(db.ProductPackageCategories, "Id_ProductPackageCategory", "Name", person.Id_ProductPackageCategory);

            return PartialView("_EditPerson", person);
        }

        [HttpPost]
        public ActionResult EditPerson(Person person)
        {
            ViewBag.Id_ProductPackageCategory = new SelectList(db.ProductPackageCategories, "Id_ProductPackageCategory", "Name", person.Id_ProductPackageCategory);

            if (ModelState.IsValid)
            {
                ModelStateDictionary errorDictionary = Validator.isValid(person);

                if (errorDictionary.Count > 0)
                {
                    ModelState.Merge(errorDictionary);
                    return View(person);
                }

                db.Persons.Attach(person);
                db.ObjectStateManager.ChangeObjectState(person, EntityState.Modified);
                db.SaveChanges();
                return View("Index");
            }

            return View(person);
        }

My partial view :

@model BuSIMaterial.Models.Person

<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
    <h3 id="myModalLabel">Edit</h3>
</div>
<div>

@using (Ajax.BeginForm("EditPerson", "Person", FormMethod.Post,
                    new AjaxOptions
                    {
                        InsertionMode = InsertionMode.Replace,
                        HttpMethod = "POST",
                        UpdateTargetId = "table"
                    }))
{

    @Html.ValidationSummary()
    @Html.AntiForgeryToken()

    <div class="modal-body">
       <div class="editor-label">
            First name :
        </div>
        <div class="editor-field">
            @Html.TextBoxFor(model => model.FirstName, new { maxlength = 50 })
            @Html.ValidationMessageFor(model => model.FirstName)
        </div>
        <div class="editor-label">
            Last name :
        </div>
        <div class="editor-field">
            @Html.TextBoxFor(model => model.LastName, new { maxlength = 50 })
            @Html.ValidationMessageFor(model => model.LastName)
        </div>
        <div class="editor-label">
            National number :
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.NumNat, new { maxlength = 11 })
            @Html.ValidationMessageFor(model => model.NumNat)
        </div>
        <div class="editor-label">
            Start date :
        </div>
        <div class="editor-field">
            @Html.TextBoxFor(model => model.StartDate, new { @class = "datepicker", @Value = Model.StartDate.ToString("yyyy/MM/dd") })
            @Html.ValidationMessageFor(model => model.StartDate)
        </div>
        <div class="editor-label">
            End date :
        </div>
        <div class="editor-field">
            @if (Model.EndDate.HasValue)
            {
                @Html.TextBoxFor(model => model.EndDate, new { @class = "datepicker", @Value = Model.EndDate.Value.ToString("yyyy/MM/dd") })
                @Html.ValidationMessageFor(model => model.EndDate)
            }
            else
            {
                @Html.TextBoxFor(model => model.EndDate, new { @class = "datepicker" })
                @Html.ValidationMessageFor(model => model.EndDate)
            }
        </div>
        <div class="editor-label">
            Distance House - Work (km) :
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.HouseToWorkKilometers)
            @Html.ValidationMessageFor(model => model.HouseToWorkKilometers)
        </div>
        <div class="editor-label">
            Category :
        </div>
        <div class="editor-field">
            @Html.DropDownList("Id_ProductPackageCategory", "Choose one ...")
            @Html.ValidationMessageFor(model => model.Id_ProductPackageCategory) <a href="../ProductPackageCategory/Create">
                Add a new category?</a>
        </div>
        <div class="editor-label">
            Upgrade? :
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Upgrade)
            @Html.ValidationMessageFor(model => model.Upgrade)
        </div>
    </div>
    <div class="modal-footer">
        <button class="btn btn-inverse" type="submit">Save</button>
    </div>
}

Any idea on what's going on?

回答1:

Try this first, just above @Html.ValidationSummary() in the partial view where you have the modal head, body and footer, place:

@Html.HiddenFor(model => model.PersonId) // or.Id whatever's in your model

This creates a hidden field in your view and sets model ID i.e. PK.