I’m working on an MVC site with Entity Framework Code First, using Ninject for DI to the controllers, and I’ve run into a design question. I’ve seen two methods used for updates with Code First. The first uses a “get by id,” changes the values of the object returned, then calls Context.SaveChanges(), like this:
Controller:
[HttpPost]
public ActionResult Edit(int id, FormCollection collection)
{
//Create a vm to hold the data from the form.
var sectionVm = new SectionEditViewModel();
//Copy the data from the http header to the object.
UpdateModel(sectionVm);
//Get the object from the database.
//_sectionRepository is injected in to the constructor.
var section = _sectionRepository.GetById(sectionVm.SectionId);
//Map from the view model to the actual model.
var viewSection = Mapper.Map(sectionVm, section);
_sectionRepository.Update();
return RedirectToAction("Index");
}
Repository:
public void Update()
{
_context.SaveChanges();
}
The second method creates the model object, attaches it to the context, changes the state of the object, then calls SaveChanges(). Illustrated here with a test method as the consumer:
Test:
[TestMethod]
public void CanUpdateSection()
{
var repo = new SectionRepository();
var testSection = GetMockSection();
testSection.SomeProperty = "A new value";
testContact.AnotherProperty = "Another new value";
repo.Update(testSection);
var persistedUpdatedSection = repo.GetById(testSection.Id);
Assert.IsNotNull(persistedUpdatedSection);
CompareSections(testSection, persistedUpdatedSection);
}
Repository:
public void Update(Section entity)
{
using(var context = new SectionContext())
{
context.Sections.Attach(entity);
context.Entry(entity).State = System.Data.EntityState.Modified;
context.SaveChanges();
}
}
Which way is preferable, or is there another, better way?
The first way is better. If you keep the SaveChanges() method in it’s own Repository method, you can make many edits and then attempt to commit them all at once using Update(). If there is an issue with one edit, all your changes will be rolled back when Update() is called.