MVC 3 Master / Detail UpdateModel inserts new detail records instead of updating existing records

1.9k views Asked by At

Ok, I've read Phil Haack's article on binding to a list and I've got that working fine on one view. But what I'm stuck when doing it off a master record.

I've got a really simple form for this object

public class Master
{
    public int ID { get; set; }
    public string MasterTitle { get; set; }
    public virtual IList<Detail> Details { get; set; }
}

public class Detail
{
    public int ID { get; set; }
    public string DetailName { get; set; }
    public virtual Master Master { get; set; }
}

The form collection comes back with the expected prefixes:

    [0] ""  
    [1] "ID"    
    [2] "MasterTitle"   
    [3] "Details[0].ID" 
    [4] "Details[0]"    
    [5] "Details"   
    [6] "Details[0].DetailName" 
    [7] "Details[1].ID" 
    [8] "Details[1]"    
    [9] "Details[1].DetailName" string

And the Controller.UpdateModel(master) binds all the properties correctly. But when I call dbContext.SaveChanges it issues the follow sql from sql profiler (psuedo code)

update detail1 set masterID = null
update detail2 set masterID = null
update master set masterName = 'newname'
insert detail1 ...
insert detail2 ...

I've got a work around that works but it's pretty hackish and I'm currently not matching up the keys so it's dependent on everything coming back in the right order. Plus I've got to include all the fields that I want updated.

    public ActionResult Edit(FormCollection collection)
    {
        try
        {
            using (var ctx = new PlayContext())
            {
                var id = int.Parse(collection["ID"]);
                Master master = ctx.Master.Find(id);

                UpdateModel(master, new [] {"MasterTitle"});
                for (int i = 0; i < master.details.Count; i++)
                {
                    UpdateModel(master.details[i], "Details[" + i + "]", new[] { "DetailName" });
                }

                ctx.SaveChanges();
                return View(master);
            }
        }
        catch (Exception e)
        {
            ModelState.AddModelError("", e);
        }
        return View();
    }

I've got a feeling that UpdateModel is somehow removing and re-adding the children.

Has anyone else got this to work? Of course, I could throw in the towel and parse the indexed field names myself, but I'm so close!

1

There are 1 answers

0
minion On

It should work - I haven't had any problems with similar code in MVC2.

I'm worried about this line though: [5] "Details"

What's it sending back in details? I expect this could be causing the problem - Not entirely sure how the model binder works in MVC 3, but I'd expect this line would cause it to set the Details collection to NULL.

You shouldn't have to rely on the fields returning in a specific order - the binder would be designed to handle them in any order.