Updating related data with Entity Framework 6 in MVC 5
Using EntityFramework 6, I would like to update the 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 updated from the edit view. However, I am doing two _db.SaveChanges();
in my controller. Is there a less complicated way to update Customer
? Since it Customer
has many properties, I would rather not do manual mapping of all parameters on Customer
and vm.Customer
.
I found the following resources:
- the official asp.net seems too complicated (see the section Adding a Course Assignment on the instructor edit page) plus would have required me to explicitly write all the Client parameters)
- this popular thread on SO. Method 3 looks like what I need, but I was unable to update the navigation property.
source to share
I don't think there is a need to call 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();
source to share