3

Using EntityFramework 6, I would like to update Customer in the following scenario:

public class Customer
{
    public int Id {get; set;}
    // 100 more scalar properties
    public virtual IList<Consultant> Consultants {get;set;}
}

public class Consultant
{
    public int Id {get; set;}
    public virtual IList<Customer> Customers{get;set;}
}

This is my ViewModel for the edit view:

public class CustomerViewModel
{
    public string[] SelectedConsultants { get; set; }
    public IEnumerable<Consultants> AllConsultants{ get; set; }
    public Customer Customer{ get; set; }
}

This is my Edit-ActionMethod:

    [HttpPost]
    public ActionResult Edit(CustomerViewModel vm)
    {
        if (ModelState.IsValid)
        {
            // update the scalar properties on the customer
            var updatedCustomer = vm.Customer;
            _db.Customers.Attach(updatedCustomer );
            _db.Entry(updatedCustomer ).State = EntityState.Modified;
            _db.SaveChanges();

            // update the navigational property [Consultants] on the customer
            var customer = _db.Customers
                        .Include(i => i.Customers)
                        .Single(i => i.Id == vm.Customer.Id);

            Customer.Consultants.Clear();
            _db.Consultants.Where(x => vm.SelectedConsultants
                       .Contains(x.Id)).ToList()
                       .ForEach(x => customer.Consultants.Add(x));

            _db.Entry(customer).State = EntityState.Modified;
            _db.SaveChanges();
            return RedirectToAction("Index");
        }
        return View(vm);
    }

This works and both scalar properties and consultants are updateable from the edit view. However, I am doing two _db.SaveChanges(); in my controller. Is there a less complex way to update Customer? Because Customer has many properties, I'd preferably not do a manual matching of all parameters on Customer and vm.Customer.

I have found the following resources:

  1. asp.net official seems overly complicated (see section Adding Course Assignments to the Instructor Edit Page) plus would require me to explicitly write all parameters of Customer)
  2. this popular thread on SO. Method 3 looks like what I need but I could not get the navigational property updated.
Community
  • 1
  • 1
peter
  • 2,103
  • 7
  • 25
  • 51

1 Answers1

0

I don't think it's necessary to call the SaveChanges twice.

Have you tried something like this:

      var customer = _db.Customers
                        .Where(c => c.Id== vm.Customer.Id)
                        .Include(c => c.Consultants)
                        .SingleOrDefault();

      customer.Consultants = _db.Consultants
                                .Where(x => vm.SelectedConsultants.Contains(x.Id)).ToList();

      _db.SaveChanges();

Edit:

Ok, not sure if this will work, but you can try using Automapper:

            var customer = Mapper.Map<Customer>(vm.Customer);
            _db.Entry(customer).State = EntityState.Modified;

            customer.Consultants = _db.Consultants.Where(x => vm.SelectedConsultants.Contains(x.Id)).ToList();

            _db.SaveChanges();
Alan Macgowan
  • 481
  • 1
  • 7
  • 22
  • Hi Alan, your suggestion does not take into account the scalar properties on customer that might have been changed as well (Customer name etc.). Also, I think Entity Framework expects using .Add or .Remove to add and remove from the ICollection. EDIT: ok, I've just checked, it did save the Consultants ;o) – peter Jul 23 '15 at 14:37
  • You can try using Automapper to map the properties from the vm to the model. – Alan Macgowan Jul 23 '15 at 14:45