Abdul Ahmad
Abdul Ahmad

Reputation: 10021

modifying List of complex types EF6 MVC5

assuming I have the following:

public class Employee
    {
        public int EmployeeID { get; set; }
        public string FirstName { get; set; }
        public virtual List<LastName> LastName { get; set; }
    }

 public class LastName
    {
        public int LastNameID { get; set; }
        public new string Value1 { get; set; }
    }

and I have an index page where the model is a list of employees with the following:

@foreach (var item in Model) {
//link to Edit page where I can modify the last names in the list
@Html.ActionLink(item.LastName[someIndex], "Edit", new { id = item.EmployeeID })

and in the controller I have

public ActionResult Edit(int? id)
        {
            if (id == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }
            Employee employee = db.Employees.Find(id);
            if (employee == null)
            {
                return HttpNotFound();
            }
            return View(employee);
        }

        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Edit(Employee employee)
        {
            if (ModelState.IsValid)
            {
               //EXCEPTION HERE - 
                db.Entry(employee).State = EntityState.Modified;
                db.SaveChanges();
                return RedirectToAction("Index");
            }
            return View(employee);
        }

and an edit view like this

@model Testing123.Models.Employee

@{
    ViewBag.Title = "LastName";
}

<h2>Last Names</h2>

@using (Html.BeginForm())
{
    @Html.AntiForgeryToken()

        @Html.ValidationSummary(true, "", new { @class = "text-danger" })

        @for (int i = 0; i < Model.LastName.Count; i ++)
                {
                    @Html.TextBoxFor(m => m.LastName[i].Value1)

                   //ADDED HIDDEN FOR HERE**** Throwing new exception, see below
                    @Html.HiddenFor(m => m.LastName[i].LastNameID)


        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" value="Save" class="btn btn-default" />
            </div>
        </div>
}

When I submit this edit form, it gives me an exception :

Attaching an entity of type 'Testing123.Models.LastName' failed because another entity of the same type already has the same primary key value. This can happen when using the 'Attach' method or setting the state of an entity to 'Unchanged' or 'Modified' if any entities in the graph have conflicting key values. This may be because some entities are new and have not yet received database-generated key values. In this case use the 'Add' method or the 'Added' entity state to track the graph and then set the state of non-new entities to 'Unchanged' or 'Modified' as appropriate

Is this the correct way of modifying the List of LastName complex type object? meaning, If have 4 last names already, and I enter this view, with the text boxes, and each last name is displayed in a text box, and I change the value in the text box, will this update the last names on form submitting?

EDIT

After adding the HiddenFor helper, I'm getting the following exception now on db.saveChanges

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.

Upvotes: 0

Views: 180

Answers (1)

Josh Gallagher
Josh Gallagher

Reputation: 5329

It would be useful to see where the exception is coming from (i.e. stack trace), but in the absence of that there are a few things I'd point out.

  1. In the Edit action you check if employee is null after you've already used it to get the LastName property.
  2. The Edit view does not (or didn't before the edit) provide any mechanism to link the text boxes it generates back to the model. You should use the Html.TextBoxFor rather than Html.TextBox. Also you need to have the LastNameId referenced in an Html.HiddenFor(m => m.LastName[i].LastNameId) (inside the loop, obviously) and the EmployeeId and FirstName in Html.HiddenFor entries (outside the loop) so that when the employee is posted back all of the properties on it and its child collection are round-tripped back to the server.
  3. LastName (the type) is not a complex type because it doesn't have a [ComplexType] attribute and it does have a column that will be inferred as the primary key of the table. This distinction between complex types and normal EF entities is probably not important to answering the question, though. Have a look at this article for more information.

Upvotes: 1

Related Questions