I need to create a form to insert an Author. In that form, there will be a DropDownList for AuthorCategory. Both Author and AuthorCategory are model classes.
I created a ViewModel just for the relevant fields of creating an author, which have public properties of FullName, Email and IEnumerable. AuthorCategories will have to be pulled from the Database hence my question is:
Which way is the correct way of binding the dropdown with the categories;
1: Have the controller action to populate the data and pass the viewmodel to the view
2: Have the relevant property in the ViewModel getter access db and return a list such as:
public List<AuthorCategory> Categories
{
get
{
using (DAL.AdminDbContext db = new DAL.AdminDbContext())
{
return new List<AuthorCategory>(db.AuthorCategories.ToList());
}
}
}
3: Directly access the db from the View
4: ViewBag / ViewData?
5: Use AutoMapper?
How this is generally handled? Any ideas would be appreciated.
I would recommend using your ViewModel as a dummy data transfer object, option#2 is excluded. The role of ViewModel is to transfer data needed for the View. Apart it is good to have Model that is mapped to you database table. So here comes Automapper as it simplifies getting ViewModel out of Model and vice versa. Controller retrieves data from DB into Model and ViewModel is populated say with Automapper.
Option #3 of directly accessing the db from the View is not a good idea. Such code will be hard to debug and test. No separation of concerns.
Option #4 of using ViewBag/ViewData for such purposes is not a good one. There are a lot of mechanisms in razor view engine that rely on #Model present in View.
Related
Team,
I am new to MVC and need some suggestion, well I have come across a situation where in I have to put multiple objects on a same view e.g. display employee, dept, etc details on same page for this I have appropriate models and since single model object is passed from controller to view I have created a view model which contain instance of the all the model my first query is
Below viewmodel EmpVM - Is this the right approach for passing object from controller to view this class will be instantiated in controller of particular view.
In case I have multiple entries of a entity i.e. address(shipping and billing) in address table is it fine to declare two instance of object in viewmodel or declare a single list and iterate in view to populeate one in grid and another in controls.
**
public class EmpVM
{
List<Address> multiAddObj{get;set}
Address singAddobj{get;set;}
}
**
Any suggestion/help on this will be of gr8 help.
Thanks in advance.
HSR.
It is perfectly OK to have a ViewModel object which encapsulates multiple model objects. You did right.
It depends on what's logically "correct" to your applications. For some purposes you should create an IEnumerable object and iterate it in the view, while in other cases it would make more sense to simply have to model objects in the ViewModel.
I am getting confused about the use of ViewModels in an edit form where one of the properties is the editable entity ie
ViewModel
Entity
Actions
The model desclaration at the top of the View page:
#model MyProject.Models.ViewModel
Not
#model MyProject.Models.Entity
So what is the best way to represent the Entity Property which is the one that needs updating. I first started making a variable out of it.
Entity myEntity = ViewModel.Entity;
So each form element edit field might be represented by:
#Html.EditorFor(model => myEntity.Name)
However what happens with the Model Binding parameters in the post action?
[HttpPost]
public ActionResult Edit(Entity myEntity)
db.Entities.Attach(myEntity);
db.ObjectStateManager.ChangeObjectState(myEntity, EntityState.Modified);
db.SaveChanges();
So this question is really about how to deal with editable property objects in a ViewModel as opposed to a specific Entity Object that could be passed in as the Model which is straight forward.
Answer most likely simple.
Huge thanks in advance.
EDIT:
Feedback on how to reference domain objects from a ViewModel in a View. I have found that if I reference them directly in the lambda expresions, then model binding works fine as it can use the derived ids to navigate around the returned ViewModel. If one use a local variable in the View then this variable name is then used in the Id which then breaks the ViewModel Model binding mapping.
Your POST action should take the view model as parameter, not the domain model:
[HttpPost]
public ActionResult Edit(ViewModel viewModel)
then you should use the ID of this viewModel to retrieve the corresponding domain model from the database that needs to be updated. And then update the properties of this domain model from the view model. Finally persist the domain model back to the database.
At the start of the development I faced with problem called "an impedance mismatch between domain model and the view". To solve this problem I decide to use ViewModel pattern - for every view (that is strongly typed) we create viewmodel class. But where is the validation logic is locate - in viewmodel classes or in our domain model objects? And where we need to perform operations to query database - in controller action, and then populate viewmodel or straight in viewmodel?
Thank you.
You should have validation logic for the viewmodel. This is what the view sends and what should be validated. As far as populating the viewmodel is concerned here's how to proceed: write a repository which queries the database and returns models. Then map those models to viewmodels (AutoMapper can help you here). Finally return viewmodels to the view. This also works the other way around: the users POSTs some data to a controller action as the form of a viewmodel which once validated is mapped back to a model and passed to the repository for update.
As an alternative to Data Annotations you may take a look at FluentValidation for validating your view models. It integrates nicely with ASP.NET MVC.
I am somewhat confused on how to properly use LINQ in combination with an ASP.NET MVC strongly typed view.
My situation is as followed.
1) I retrieve a single object through LINQ
2) I pass this LINQ object to a strongly typed view. (edit form)
3) The user submits the form and the controller receives the LINQ object.
So my questions are:
1) Is the object the controller method receives after the submit still tight to the original datacontext or is it a newly created instance?
2) What is the preferred way to store the updated values in the database using LINQ. If it is still tight to the original datacontext a simple call to SubmitChanges() would be sufficient. But how to maintain the datacontext?
I would like to be able to save these data objects without having to use really ugly linq update statements. (Like retrieving the row again and manually update its values)
Any help, insights and preferably code samples would be appreciated.
Regards,
Dennis
You should fetch the existing object again, and update it, somthing like:
public ActionResult Edit(int ID)
{
DataEntity entity = _service.GetMyEntity(ID);
UpdateModel(entity);
//Saving code goes here.
return View();
}
The entity that you are talking about retrieving is no longer attached to the data context.
Is the object the controller method
receives after the submit still tight
to the original datacontext or is it a
newly created instance?
It won't be attached to a DataContext at all on Submit.
What is the preferred way to store the
updated values in the database using
LINQ. If it is still tight to the
original datacontext a simple call to
SubmitChanges() would be sufficient.
But how to maintain the datacontext?
The preferred way is to create a new DataContext, retreive the old object from the database, update the fields based on what was submitted to your Form, and then save the updated copy from the new Context.
Use your linq objects to get the data and put it into a POCO (plain old c# object) Model specifically for your view.
Your linq2sql/ef objects can be structured to store data which do not necessarily reflect your views
Your model can be updated and validated by the MVC framework by placing it in the call to the post.
public ActionResult EditPost(EditModel model)
When you have a valid model you can then transfer the data back to the database via your linq2sql/ef objects
if(ModelState.IsValid) // save to db
Create a DataContext when you need to load and save, don't persist it
1) It is a new instance (through model binding feature) and it is not attached.
2) It depends, but the best would be probably new instance using(var context = new DBContext()) etc.
3) The most simple thing is fetch the object, pass in the updated values and SubmitChanges() (as you describe). Other option is described in this article. You create new instance of the object (or you have it from the model binding), attach it to the context and submit changes:
public ActionResult Test(MyModel model)
{
DbContext.Models.Attach(model);
DbContext.Refresh(RefreshMode.KeepCurrentValues, model);
DbContext.SubmitChanges();
}
Situation: In some project management software written in asp.net I have a create project page (working fine). I need to add to this the ability to add tasks from a list of templates to this project pre-creation BUT the list of available tasks is dependent on some values sitting in the create form.
My abstract solution is this:
I have a "Create" view and an "Add Tasks" View - both strongly typed to a composite viewModel defined in the controller
My Create method checks which button was used to call it - if the
button was "Add Tasks" it then renders the AddTasks view, passing the model in from the create view, again all in the same controller.
The AddTasks View posts to the Create view with one of two buttons, one loads the view and the other causes an actually DB save.
My Problem is this:
The different views use different properties of the same model, but in passing this model between them, the data is reset (in any case reload or save).
I am guessing this is happening from auto binding of data - though I thought fields not present on the form would not overwrite existing model data passed down.
There is hardly any code in the controller manipulating the model at present - It is only passed from view to view in these cases.
This is the controller code:
// POST: /Project/Create/<viewModel>
[Authorize, AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create([Bind(Exclude = "Id,id")] ProjectViewModel model)
{
if (model.SubmitValue == "Create")
{
try
{
model.Project.Id = Guid.NewGuid();
model.Save(this.User.Identity.Name);
return this.RedirectToAction("Details", new {id = model.Project.Id});
}
catch (Exception e)
{
this.ModelState.AddModelError(e.ToString(), e.ToString());
}
return View(model);
}
if(model.SubmitValue == "AddTasks")
{
return this.View("AddTasks",model);
}
return this.View(model);
}
//POST: /Project/AddTasks/ + model
[Authorize, AcceptVerbs(HttpVerbs.Post)]
public ActionResult AddTasks([Bind(Include = SelectedCarrierTasks")]ProjectViewModel model)
{
return View(model);
}
The Question is: How do I maintain the state of the model across these views until it finally save it?
I would prefer to avoid any hackish (TempData) or JS dependant solutions, but I am not closed to these if they are really the best solution.
Thanks,
Adam Tolley
One simple solution is to persist the ViewModel object in a Session variable and bind the View from this source.I ts certainly not the most elegant solution. Another option, and probably less elegant one is persist this model data in the database, with some temporary/unsaved flag.
The problem is that when you display the add tasks view you're not providing fields for your "Project" object therefore the ModelState loses the data related to the project, you will need to provide this fields to ensure you're not loosing that data.
You don't need to display this fields they can be of type hidden and they will preserve the value. Just make sure that if you will be binding to a view model you will need to name this fields correctly like this Model.Project.Property.
Perhaps I am trying to solve the wrong problem (ala Bruce Eckel). I am going to try to move to a structure that needs this sort of fuzzy boundary less. I don't want to adopt a REST paradigm only to shoe-horn it into a stateful application.
Possibly these controls belong on the same page, and I can use some JQuery goodness to put in a tab pane for easiness on the eyes.
Thanks to those who answered, I found each useful and will try to remember to up-vote them as soon as I have some more rep.
I can't comment on other peoples questions at the moment, but the only real option is the session if you want to persist an objects state during web requests, or serializing it and placing it in a hidden field.
Or a final option would be to change the way your pages work so you can save the object after each request...
If your using nHibernate then you might want look into the Conversations pattern, but this just essentially saves the nHibernate session into the asp.net session anyway...