In my MVC application, I normally have ViewModel
for such actions as Edit
, mainly for populating selection lists for the properties to modify. For example my Model
looks like this:
class MyModel{
public int? NavPropID {get; set;}
public AnotherModel NavProp {get; set;}
...
}
Now I was wondering, how should I design my ViewModel
to reference the NavProp.
class MyViewModel{
public int? NavPropID {get; set;}
public AnotherModel NavProp {get; set;}
...
}
Should I use both NavPropID
and NavProp
, or should I use only one (which?) in the ViewModel
?
I wanted to use only NavProp
at first, because it feels more natural to me (I feel it hides the database implementation detail and it is how I do in WPF and MVVM). But then in my Edit view, I have something like this:
@Html.DropDownListFor(model => model.NavProp,
new SelectList(Model.AllAnotherModels.Select(
i => new {Item = i, Text = i.Name}), "Item","Text"))
In the postback of Edit action, I can see that NavProp
is not correctly bonded by the binder because the attemptedValue is of type string and the value is the class name of NavProp (which I guess means it uses ToString() method to post back to the controller). How can I make it work for the post back action?
I then tried to only have NavPropID
in the ViewModel
. But there are two problems: 1) it means I have to load the actual NavProp
in the controller before I use AutoMapper
to map back from ViewModel
to Model
. I feel that this is beyond the responsibility of a controller and 2) even if I load the actual property in the controller, I have some problem later when I am updating by calling DBSet.Attach().
So what is the best practice for the ViewModel
to reference a navigational property in the Model
?
UPDATE:
Here is my post back function of the Edit
action. It is generic I think so I didn't paste it in the first place.
[HttpPost]
public ActionResult Edit(MyViewModel vm)
{
if (ModelState.IsValid)
{
... // I use Automapper to map back to Model and then
// use UnitOfWork and Repository to update the Model
}
}
And my ModelState.IsValid
is false so it can't proceed. As I mentioned, I then checked the ModelState (a dictionary) and found out that NavProp
is invalid and the attemptedValue
is the class name while I think it should be the actual value of the property.