2

Am having trouble finding a clear answer to my situation when searching Stack Overflow and Google, hopefully someone can point me in the right direction.

My Situation I want to be able to use a single edit form (in a single View) to update a 3-level-deep hierarchical entity using ASP.NET MVC 3 and Entity Framework 4 CTP (Code-first) - the model consists of Services, which can have many Service Options, which in Turn can have many Inventory Items.

I was expecting to be able to use MVCs default model binder (via TryUpdateModel) to:

  1. Update an existing 'Service' record
  2. Add/Update/Delete 'Service Option' records (attached to the Service) depending on posted values
  3. Add/Update/Delete 'Inventory' records (attached to each Service Option) depending on posted values

My Model

    [Bind(Include="Name, ServiceOptions")]
public class Service {
    [Key]
    public int ServiceID { get; set; }      
    public string Name { get; set; }        
    public DateTime DateCreated { get; set; }
    public virtual ICollection<ServiceOption> ServiceOptions { get; set; }
}

[Bind(Include="ServiceOptionID, Description, Tags")]
public class ServiceOption {
    [Key]
    public int ServiceOptionID { get; set; }
    public int ServiceID { get; set; }  /* parent id reference */
    public string Description { get; set; }
    public virtual ICollection<Inventory> InventoryItems { get; set; }
}


[Bind(Include = "InventoryID, Description")]
public class Inventory {
    [Key]
    public int InventoryID { get; set; }
    public int ServiceOptionID { get; set; }  /* parent id reference */
    public string Description { get; set; }
}

Ideal Controller Method:

    [HttpPost]
public ActionResult EditService(int id) {
    Service service = db.Services.Single(s => s.ServiceID == id);
    TryUpdateModel(service); // automatically updates child and grandchild records

    if (ModelState.IsValid) {               
        db.SaveChanges();
        return RedirectToAction("Index");
    }
    return View(service);
}

Is there a way to achieve this utopian dream, or am I barking up the wrong tree? I'm open to using another technology (such as normal EF4, Automapper etc)

Thanks in advance!

Brendan
  • 1,033
  • 10
  • 12

1 Answers1

0

With just the default model binder? Probably not.

With a custom one? Probably.

However your issue won't be the model binder itself. Your issue will be that EF and ORMs and ( I think ) in general do not consider removing an item from a collection as a delete operation. In effect what you are telling the ORM is the relationship does not exist, not that a child row needs to be deleted. Depending on your mappings you'll usually get an error like "A referential integrity constraint violation occurred". This won't be because of code first this is just how EF works.

EF works this way by design and is really important for more complex relationships such as when you have m2m relationships which reference other m2m relationships. You really want EF to be able to disambiguate calls for removal of a relationship and calls to remove a row entirely.

Also, IMHO, this technique is also bad because your letting the piece of code responsible for mapping http values also dictate how objects should be persisted. This is a bad move. I consider delete operations a pretty sacrosanct act and shouldn't be left to the ModelBinder alone. Without soft deletes or logging deleting objects should be considered "serious business".

John Farrell
  • 24,673
  • 10
  • 77
  • 110
  • Thanks jfar.. So if you needed to post a single form, which took the updates to an entity, its children AND grandchildren - how would you go about it? With DTOs? Then manually update the entity graph to reflect the DTO contents before saving? – Brendan Jan 25 '11 at 00:23