Update entity with ViewModel and Entity Framework 6? - asp.net-mvc

I've been looking around and can't quite find the answer. I'm using a ViewModel in my Edit View so that I can have values for some dropdownlist. Now when I go to update my DB I'm not understanding how I can update my database record. I'm guessing I could create a new entity object, do a Find, and then update each property based on the ViewModel passed in from the Form but that sure seems like a lot of manual work.
Here I'm using the VeiwModel in the Edit View.
#model CPPCustomerCall.ViewModels.CustomerCallVM
Here is my controller's ActionResult. I changed the object type of the ActionResult to take in CustomerCallVM instead of the CustomerCall which was auto-generated. I assume since the Edit View's model is the ViewModel that's the type of object the ActionResult will receive. However, my ViewModel has more properties that aren't needed for the Entity Model to update the record. How do I go about updating my DB record in this ActionResult?
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Edit([Bind(Include = "Id,CustomerName,Subject,PhoneNumber,CallMessage,CallDate,Status,CallNotes")] CustomerCallVM customerCall)
{
if (ModelState.IsValid)
{
db.Entry(customerCall).State = EntityState.Modified;
await db.SaveChangesAsync();
return RedirectToAction("Index");
}
return View(customerCall);
}

First, Bind and view models are mutually exclusive. If you don't want something to be eligible to be modified, then it shouldn't be on your view model, in the first place. Barring that, view models diverge from entities in the sense that they can't be saved directly. As a result, there's always some intervention present on your part to map the posted values back onto the entity, which means you can then selectively not map over certain properties that shouldn't be, regardless of whether they were posted or not. Long and short, get rid of the Bind stuff. It's just something else to maintain and a huge source of potential bugs.
That said, the code you have is workable; you're just missing the crucial part where you map the data from your view model back onto your entity. First, you need to fetch the entity from the database so you have a base to work from:
var customerCall = db.CustomerCalls.Find(id);
if (customerCall == null)
{
return new HttpNotFoundResult();
}
FWIW, your edit route should include the id in the route, according to REST conventions. Following REST isn't strictly required, but it's certainly recommended. While a web application adhering to REST doesn't mean it's a good application, not adhering to rest is generally a sure sign of a badly designed and coded application.
Then, you map over your properties. You can either do this manually:
customerCall.CustomerName = model.CustomerName;
// etc.
Or you can use a library like AutoMapper.
mapper.Map(model, customerCall);
AutoMapper requires a bit of initial setup to make this magic work, of course, so review the docs, if you're going that route. Manual mapping is easier, but far more tedious and repetitive.

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Edit([Bind(Include = "Id,CustomerName,Subject,PhoneNumber,CallMessage,CallDate,Status,CallNotes")] CustomerCallVM customerCall)
{
if (ModelState.IsValid)
{
// Find The record you need
var dbObj = CustomerCalls.FirstOrDefault(x=> x.id = customerCall.id);
//Check if null
if(dbObj == null) dbObj = new CustomerCall();
/// Map your properties
// Add object to the stack
if(dbObj.id == 0){
CustomerCalls.Add(dbObj);
}else{
CustomerCalls.Update(dbObj);
}
await db.SaveChangesAsync();
return RedirectToAction("Index");
}
return View(customerCall);
}

Related

Add to DB using SaveChanges() in Entity Framework with object from another scope

I'm new using entity framework, and I'm trying to insert into the DB.But I'm having an issue, because I need to only SaveChanges from objects of other 3 scopes. Like this:These are my three Actions that Add the objects into my entities:
public void AddEndereco(entidade_endereco entEndereco)
{
db.entidade_endereco.Add(entEndereco);
}
public void addContato(entidade_contato entContato)
{
db.entidade_contato.Add(entContato);
}
public void addBanco(entidade_banco entBanco)
{
db.entidade_banco.Add(entBanco);
}
And in this action I need to insert all the objects into my DB:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(entidade entidade, string Grupo, string Situacao)
{
if (ModelState.IsValid)
{
if (Grupo != "")
entidade.gre_codigo = Convert.ToInt32(Grupo);
if (Situacao != "")
entidade.sie_codigo = Convert.ToInt32(Situacao);
if (entidade.ver_ativo)
entidade.ent_ativo = "S";
else
entidade.ent_ativo = "N";
if (entidade.ver_cliente)
entidade.ent_cliente = "S";
else
entidade.ent_cliente = "N";
if (entidade.ver_fornecedor)
entidade.ent_fornecedor = "S";
else
entidade.ent_fornecedor = "N";
//ADDING ANOTHER OBJECT
db.entidades.Add(entidade);
//HERE IS WHERE I NEED TO SAVE ALL (entidade_endereco, entidade_contato, entidade_banco, entidade)
db.SaveChanges();
return RedirectToAction("Index");
}
return View(entidade);
}
But it is only saving the entidade object, the others don't exist anymore when db.SaveChanges() is executed.
How can I insert into the DB with objects that were added to my entity in other scopes?
If you really want to make this work as is, you would need to store either the Context (really bad idea) or Entities (slightly less bad) across requests. Session State jumps to mind, but using it can bring in a whole load of new pain.
Ideally, you should change your design to take advantage of the stateless nature of HTTP. Each action method should be a separate transaction, saving the data from it's execution when the method is done. If those separate entities only make sense when they are all saved together, then you need to create all of them within a single action and save them to the context together. Managing the boundaries of different business entities and when they are saved is a critical part of application design, I highly recommend you read about Aggregate Roots within Domain Driven Development. Even if you don't go the full DDD route, the Aggregate Root concept will be extremely helpful to you. The CQRS Journey from Microsoft gives an in-depth tutorial of these concepts (and many others)
Im not sure, if I got your question right (excuse my poor spanish). In the Action Create you only add "entidade" to your entidades collection, and so its the only one affected by SaveChanges(). If you want to add others, include in the Create-Action or try making a EF-transaction.
Without transaction the context is lost after the Create-Method ends

MVC index method with change to viewmodel

I want to know the best way of writing an index method in MVC when we need to make changes to the model before passing it to the view.
I picked up a technique from somewhere where you can pass in the model you intend to pass to your view, and make changes to it, but we have noticed that model binding kicks in when passing to the index method, and validation fires, when there is no need for it to because it is the initial load.
For example, which is more correct:
public ActionResult Index(ViewModel model)
{
model.SomeProperty = "MyNewValue";
return base.Index(model);
}
OR
public ActionResult Index()
{
ViewModel model = new ViewModel();
model.SomeProperty = "MyNewValue";
return base.Index(model);
}
and is there anything I should know about the implications of using either one?
With initial loads, the latter makes more sense. Controllers in MVC are newed up each and every single time you use them. There is no persistence whatsoever. With the first option, HTTP requests need some pre-existing knowledge of your API. So, the recommendation is to have the view model come from a persistence layer.
public ActionResult Index()
{
var vm = /* persistence layer */
vm.SomeProperty = "NewVal";
return View(vm);
}

Should we check id in POST action edit or not?

I see everywhere (in each tutorial) something like that:
public ActionResult Edit(int id = 0)
{
Employee employee = db.Employees.Find(id);
if (employee == null)
{
return HttpNotFound();
}
return View(employee);
}
[HttpPost]
public ActionResult Edit(Employee employee)
{
if (ModelState.IsValid)
{
db.Entry(employee).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(employee);
}
So in GET action edit we check if id exists but in POST action edit not. Shouldn't we check also id in POST action edit? I mean something like that:
[HttpPost]
public ActionResult Edit(Employee employee)
{
// Check if employe exists in database:
Employee employeeFromDB = db.Employees.Find(employee.id);
if (employeeFromDB == null)
{
return HttpNotFound();
}
if (ModelState.IsValid)
{
db.Entry(employee).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(employee);
}
Or maybe this isn't necessary because database doesn't allow to save employee with bad id? What do you think?
It's actually not necessary, for the reason you note; Your code is going to result in an UPDATE command, but if the id of the entity is not valid, you'll get an error. There's no need to explicitly load it again, for purposes of checking the existence of an entity matching the id...
That said, there are possibly other reasons you want to do that. For instance, to make sure the logged-on user is allowed to edit that particular entity.
One thing I would address earlier rather than later is decoupling your entity model from your view, this is not good practice. What if your entities contain sensitive data? or complex models? This data is viewable in the browser. You potentially end up passing additional data to your view and end up with 'fat' models, keep them small and necessary.
With a View Model you can apply validations to them which will handle your problem for you. These errors will then populate when you call ModelState.IsValid and pass them back to the view. I use Fluent Validation instead of the default MVC annotations out of preference. But check out both / similar and see which suits you.
By separating out your validations into your view model you keep your controllers nice and tidy. It's more effort of course as you need to map them back and forth from your database, but it gives you a great deal of flexibility whereby you can extend them, add validations etc.
There is nothing wrong with doing a sanity check imho. If nothing to give you some error during the development phase.

Fetching data within an ASP.NET MVC ViewModel class?

For those that create ViewModels (for use by typed views) in ASP.NET MVC, do you prefer to fetch the data from a service/repository from within the ViewModel, or the controller classes?
For example, we started by having ViewModels essentially being DTOs and allowing our Controllers to fetch the data (grossly oversimplified example assumes that the user can only change employee name):
public class EmployeeViewModel
{
public String Name; //posted back
public int Num; //posted back
public IEnumerable<Dependent> Dependents; //static
public IEnumerable<Spouse> Spouses; //static
}
public class EmployeeController()
{
...
public ActionResult Employee(int empNum)
{
Models.EmployeeViewModel model = new Models.EmployeeViewModel();
model.Name = _empSvc.FetchEmployee(empNum).Name;
model.Num = empNum;
model.Dependents = _peopleSvc.FetchDependentsForView(empNum);
model.Spouses = _peopleSvc.FetchDependentsForView(empNum);
return View(model);
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Employee(Models.EmployeeViewModel model)
{
if (!_empSvc.ValidateAndSaveName(model.Num, model.Name))
{
model.Dependents = _peopleSvc.FetchDependentsForView(model.Num);
model.Spouses = _peopleSvc.FetchDependentsForView(model.Num);
return View(model);
}
this.RedirectToAction(c => c.Index());
}
}
This all seemed fine until we started creating large views (40+ fields) with many drop downs and such. Since the screens would have a GET and POST action (with POST returning a view if there was a validation error), we'd be duplicating code and making ViewModels larger than they probably should be.
I'm thinking the alternative would be to Fetch the data via the Service within the ViewModel. My concern is that we'd then have some data populated from the ViewModel and some from the Controller (e.g. in the example above, Name would be populated from the Controller since it is a posted value, while Dependents and Spouses would be populated via some type of GetStaticData() function in the ViewModel).
Thoughts?
I encountered the same issue. I started creating classes for each action when the code got too big for the action methods. Yes you will have some data retrieval in classes and some in the controller methods. The alternative is to have all the data retrieval in classes, but half the classes you won't really need, they will have been created for consistency sake or have all the data retrieval in the controller methods, but again, some of those methods will be too complex and needed to have been abstracted into classes... so pick your poison. I would rather have a little inconsistency and have the right solution for the job.
As for putting behavior into the ViewModel, I don't, the point of the ViewModel is to be a thin class for setting and extracting values from the View.
There have been cases where I've put conversion methods in the ViewModel. For instance I need to convert the ViewModel to the corresponding entity or I need to load the ViewModel with data from the Entity.
To answer your question, I prefer to retrieve data from with in the controller/action methods.
Typically with DropDowns, I create a dropdown service. DropDowns tend to be the same data that spans views. With the dropdowns in a service I can use them on other views and/or Cache them.
Depending on the layout, 40 plus fields could create a cluttered view. Depending the type of data, I would try to span that many fields across multiple views with some sort of tabbed or wizard interface.
There's more than that ;-) You can fetch in model binder or action filter. For the second option, check Jimmy Bogard's blog somewhere around here. I personally do it in model binders. I use ViewModel like this: My custom ASP.NET MVC entity binding: is it a good solution?. It is processed by my custom model binder:
public object BindModel(ControllerContext c, BindingContext b)
{
var id = b.ValueProvider[b.ModelName]; // don't remember exact syntax
var repository = ServiceLocator.GetInstance(GetRepositoryType(b.ModelType));
var obj = repository.Get(id);
if (obj == null)
b.ModelState.AddModelError(b.ModelName, "Not found in database");
return obj;
}
public ActionResult Action(EntityViewModel<Order> order)
{
if (!ModelState.IsValid)
...;
}
You can also see an example of model binder doing repository access in S#arp Architecture.
As for static data in view models, I'm still exploring approaches. For example, you can have your view models remember the entities instead of lists, and
public class MyViewModel
{
public MyViewModel(Order order, IEmployeesSvc _svc)
{
}
public IList<Employee> GetEmployeesList()
{
return _svc.GetEmployeesFor(order.Number);
}
}
You decide how you inject _svc into ViewModel, but it's basically the same as you do for controller. Just beware that ViewModel is also created by MVC via parameterless constructor, so you either use ServiceLocator or extend MVC for ViewModel creation - for example, inside your custom model binder. Or you can use Jimmy Bogard's approach with AutoMapper which does also support IoC containers.
The common approach here is that whenever I see repetative code, I look to eliminate it. 100 controller actions doing domain-viewmodel marshalling plus repository lookup is a bad case. Single model binder doing it in generic way is a good one.
I wouldn't be fetching data from the database in your ViewModel. The ViewModel exists to promote separation of concerns (between your View and your Model). Tangling up persistance logic in there kind of defeats the purpose.
Luckily, the ASP.NET MVC framework gives us more integration points, specifically the ModelBinder.
I've got an implementation of a generic ModelBinder pulling information from the service layer at:-
http://www.iaingalloway.com/going-further-a-generic-servicelayer-modelbinder
It doesn't use a ViewModel, but that's easily fixed. It's by no means the only implementation. For a real-world project, you're probably better off with a less generic, more customised solution.
If you're diligent, your GET methods don't even need to know that the service layer exists.
The solution probably looks something like:-
Controller action method:-
public ActionResult Details(MyTypeIndexViewModel model)
{
if( ModelState.IsValid )
{
return View(model);
}
else
{
// Handle the case where the ModelState is invalid
// usually because they've requested MyType/Details/x
// and there's no matching MyType in the repository
// e.g. return RedirectToAction("Index")
}
}
ModelBinder:-
public object BindModel
(
ControllerContext controllerContext,
BindingContext bindingContext
)
{
// Get the Primary Key from the requestValueProvider.
// e.g. bindingContext.ValueProvider["id"]
int id = ...;
// Get an instance of your service layer via your
// favourite dependancy injection framework.
// Or grab the controller's copy e.g.
// (controllerContext.Controller as MyController).Service
IMyTypeService service = ...;
MyType myType = service.GetMyTypeById(id)
if (myType == null)
{
// handle the case where the PK has no matching MyType in the repository
// e.g. bindingContext.ModelState.AddModelError(...)
}
MyTypeIndexViewModel model = new MyTypeIndexViewModel(myType);
// If you've got more repository calls to make
// (e.g. populating extra fields on the model)
// you can do that here.
return model;
}
ViewModel:-
public class MyTypeIndexViewModel
{
public MyTypeIndexViewModel(MyType source)
{
// Bind all the properties of the ViewModel in here, or better
// inherit from e.g. MyTypeViewModel, bind all the properties
// shared between views in there and chain up base(source)
}
}
Build your service layer, and register your ModelBinder as normal.
Here's another solution: http://www.lostechies.com/blogs/jimmy_bogard/archive/2009/06/29/how-we-do-mvc-view-models.aspx
Main points there:
Mapping is done by a mediator - in this case it is AutoMapper but it can be your own class (though more to code). This keeps both Domain and ViewModel concentrated on the domain/presentation logic. The mediator (mapper) will contain (mostly automatic) logic for mapping, including injected services.
Mapping is applied automatically, all you do is tell the action filter the source/destination types - very clean.
(Seems to be important for you) AutoMapper supports nested mappings/types, so you can have your ViewModel combined of several independent view models, so that your "screen DTO" is not messy.
Like in this model:
public class WholeViewModel
{
public Part1ViewModel ModelPart1 { get; set; }
public Part2ViewModel ModelPart2 { get; set; }
}
you re-use mappings for specific parts of your View, and you don't write any new line of code, since there're already mappings for the partial view models.
If you don't want AutoMapper, you have have IViewModelMapper interfaces, and then your IoC container will help your action filter to find appropriate
container.Resolve(typeof(IViewModelMapper<>).MakeGenericType(mysourcetype, mydesttype))
and it will also provide any required external services to that mapper (this is possible with AutoMapper, too). But of course AutoMapper can do recursions and anyway, why write additional AutoMapper ;-)
Consider passing your services into the custom ViewModel on its constructor (ala Dependency Injection). That removes the model population code from your controller and allows it to focus on controlling the logical flow of the application. Custom ViewModels are an ideal place to abstract the preparation of things like SelectLists that your droplists will depend on.
Lots of code in the controller for things like retrieving data isn't considered a best practice. The controller's primary responsibility is to "control" the flow of the application.
Submitting this one late... Bounty is almost over. But...
Another mapper to look at is Automapper: http://www.codeplex.com/AutoMapper
And overview on how to use it: http://www.lostechies.com/blogs/jimmy_bogard/archive/2009/01/22/automapper-the-object-object-mapper.aspx
I really like it's syntax.
// place this somewhere in your globals, or base controller constructor
Mapper.CreateMap<Employee, EmployeeViewModel>();
Now, in your controller, I would use multiple viewmodels. This enforces DRY by allowing you to reuse those viewmodels elsewhere in your application. I would not bind them all to 1 viewmodel. I would refactor to something like:
public class EmployeeController()
{
private IEmployeeService _empSvc;
private ISpouseService _peopleSvc;
public EmployeeController(
IEmployeeService empSvc, ISpouseService peopleSvc)
{
// D.I. hard at work! Auto-wiring up our services. :)
_empSvc = empSvc;
_peopleSvc = peopleSvc;
// setup all ViewModels here that the controller would use
Mapper.CreateMap<Employee, EmployeeViewModel>();
Mapper.CreateMap<Spouse, SpouseViewModel>();
}
public ActionResult Employee(int empNum)
{
// really should have some validation here that reaches into the domain
//
var employeeViewModel =
Mapper.Map<Employee, EmployeeViewModel>(
_empSvc.FetchEmployee(empNum)
);
var spouseViewModel =
Mapper.Map<Spouses, SpousesViewModel>(
_peopleSvc.FetchSpouseByEmployeeID(empNum)
);
employeeViewModel.SpouseViewModel = spouseViewModel;
return View(employeeViewModel);
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Employee(int id, FormCollection values)
{
try
{
// always post to an ID, which is the employeeID
var employee = _empSvc.FetchEmployee(id);
// and bind using the built-in UpdateModel helpers.
// this will throw an exception if someone is posting something
// they shouldn't be posting. :)
UpdateModel(employee);
// save employee here
this.RedirectToAction(c => c.Index());
}
catch
{
// check your domain model for any errors.
// check for any other type of exception.
// fail back to the employee screen
RedirectToAction(c => c.Employee(id));
}
}
}
I generally try to stay away from saving multiple entities on a controller action. Instead, I would refactor the employee domain object to have AddSpouse() and SaveSpouse() methods, that would take an object of Spouse. This concept is known as AggregateRoots, controlling all dependancies from the root - which is the Employee() object. But, that is just me.

How does the ASP.NET MVC UpdateModel() method work?

I'm working on my first .NET MVC application and using the NerdDinner tutorial as a reference point. One point that is intriguing me at the moment is the UpdateModel() method. (I don't like using things I don't really understand.)
Taken from the NerdDinner tutorial -
//
// POST: /Dinners/Edit/2
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(int id, FormCollection formValues) {
Dinner dinner = dinnerRepository.GetDinner(id);
UpdateModel(dinner);
dinnerRepository.Save();
return RedirectToAction("Details", new { id = dinner.DinnerID });
}
My main question is how does the UpdateModel() get access to the formValues passed in the Edit method? Why is the collection not passed in explicitly as a parameter to the method?
UpdateModel() is a Controller helper method that attempts to bind a bunch of different input data sources (HTTP POST data coming from a View, QueryString values, Session variables/Cookies, etc.) to the explicit model object you indicate as a parameter. Essentially, it is only for model binding.
If you express the input parameters for your Action as a strongly-typed model (like a View Model), you've already taken all of the steps that are done behind the scenes when UpdateModel() is called. If you retrieve an object from the DataContext and edit its properties, SaveChanges() is all you need to push the updates back to the database (in this case, Save()).
Example:
//
// POST: /Dinners/Edit/2
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(DinnerViewModel incoming) {
var dinner = dinnerRepository.GetDinner(incoming.DinnerID);
dinner.Description = incoming.Description;
dinnerRepository.Save();
return RedirectToAction("Details", new { id = incoming.DinnerID });
}
However, there is a use-case for using UpdateModel() with a strongly-typed model: when you are passing in a strongly-typed model and want its values to directly replace those of an entity from the database (provided they are all named and typed the same). In this case, you would retrieve the object, use UpdateModel() on it, and its model binding operation will pull in any similarly-named and typed properties from the strongly-typed object to the retrieved object. In other words, it will perform reflection for you.
So, like your example, if you want all properties to update without specifying which to update, and your strongly-typed model and database model have similarly-named properties, you would still want to use UpdateModel() to take advantage of the reflection.
Example:
//
// POST: /Dinners/Edit/2
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(DinnerViewModel incoming) {
var dinner = dinnerRepository.GetDinner(incoming.DinnerID);
UpdateModel(dinner);
dinnerRepository.Save();
return RedirectToAction("Details", new { id = incoming.DinnerID });
}
The only advantage here (over using a FormCollection object) is that you'd have access to all other properties of the strongly-typed object (as shown by incoming.DinnerID).
Conclusion: if you're translating a strongly-typed object to a derived object, it's probably easiest to use UpdateModel(). However, it's largely unnecessary if you are simply updating a few properties of the derived object. Also, be aware that use of the Entity Framework (instead of something like Linq to SQL) makes all of this moot, as it can relate strongly-typed objects and derived objects with its own methods.
It does inspect all the HttpRequest inputs such as Form, QueryString, Cookies and Server variables. I think in this order.
Instead of passing Model object as a parameter to "Post()" action method, we are creating an instance of an Model object within the "Post()" function, and updating it using "UpdateModel()" function. "UpdateModel()" function inspects all the HttpRequest inputs such as posted Form data, QueryString, Cookies and Server variables and populate the employee object.
e.g.
[HttpPost]
[ActionName("Create")]
public ActionResult Create_Post()
{
EmployeeBusinessLayer employeeBusinessLayer =
new EmployeeBusinessLayer();
Employee employee = new Employee();
UpdateModel(employee);
employeeBusinessLayer.AddEmmployee(employee);
return RedirectToAction("Index");
}

Resources