MVC4 Models Best Practice Database v View Models (Submitted for View)
I want to start with good habits from the beginning, so I have this question and problem:
I do the following which works, then I read this post
This example of what I was doing:
CONTROLLER
public ActionResult OneDollar130(Int32 number)
{
MyEDM db = new MyEDM();
MyDBModel model = db.MyTable.Where(t => t.Current == 1 && t.No == number).First();
return View(model);
}
VIEW
@model MyProject.MyDBModel
<table>
<tr>
@if (Model.fldNo1 == "")
{
<td class="numberTD">
@Html.ActionLink("1", "Number1", "Number", new { model = Model, number = 1 }, null)
</td>
}
else
{
<td class="numberTD2">
@Html.ActionLink("1", "Number2", "Number", new { model = Model, number = 1 })
</td>
}
</tr>
</table>
I am using a model from my EDM and passing it to the view.
In the post above, I read that I should not pass database models to the view, as it is bad practice. This concerns me somewhat, since I want to do it right.
So, based on the above post, I change my code to experiment and hit:
CONTROLLER
public ActionResult OneDollar112(Int32 TableNo)
{
return View(new getOneDollar112Game(TableNo));
}
MODEL
public class getMyModel
{
MyEDM db = new MyEDM();
public MyDBModel MyModel { get; set; }
public getMyModel() { }
public getMyModel(Int32 number)
{
MyModel = db.MyTable
.Where(t => t.Current == 1 && t.No == numbner).First();
}
}
VIEW
@model MyProject.Models.getMyModel
<table>
<tr>
@if (Model.fldNo1 == "")
{
<td class="numberTD">
@Html.ActionLink("1", "Number1", "Number", new { model = Model, number = 1 }, null)
</td>
}
else
{
<td class="numberTD2">
@Html.ActionLink("1", "Number2", "Number", new { model = Model, number = 1 })
</td>
}
</tr>
</table>
So my 2 questions:
-
What's the best practice ... does what I did before breaking the rule of not passing DB models to the view?
-
If the second method is correct (which I am assuming), why am I constantly getting the error that fldNo1 does not exist?
eg: CS1061: "MyProject.Models.getMyModel" does not contain a definition for "fldNo1" and does not use the "fldNo1" extension method taking a first argument of type "MyProject.Models.getMyModel" (are you missing using a directive or assembly reference?)
1) I edited your code.
Act:
public ActionResult OneDollar112(Int32 tableNo)
{
return View(new OneDollar112ViewModel(tableNo));
}
Model:
public class OneDollar112ViewModel
{
private static MyEDM db = new MyEDM();
private MyDBModel myModel;
public string fldNo1
{
get
{
return myModel == null
? myModel.fldNo1
: null;
}
set
{
// Your set logic here
}
}
public OneDollar112ViewModel(Int32 number)
{
myModel = db.MyTable
.Where(t => t.Current == 1 && t.No == numbner).SingleOrDefault();
}
}
View:
@model MyProject.Models.OneDollar112ViewModel
<table>
<tr>
@if (Model.fldNo1 == "")
{
<td class="numberTD">
@Html.ActionLink("1", "Number1", "Number", new { model = Model, number = 1 }, null)
</td>
}
else
{
<td class="numberTD2">
@Html.ActionLink("1", "Number2", "Number", new { model = Model, number = 1 })
</td>
}
</tr>
</table>
2) You should use view models to decouple your business logic from the data layer that you could encapsulate in services and use dependency injection in the future.
source to share
I also don't like using database objects as models.
What I am doing relies on the MVC framework in my project.
Views
- contains views
Models
- contains models intended for presentation
Controllers
- contains a controller also responsible for translating between the database and the view model.
In my controllers, I add repositories (see repository pattern ) to communicate with the database. If I wanted to show the user in my opinion, I would get something like this
public ActionResult Show()
{
// entity model
var user = _userRepository.GetUserByName(User.Identity.Name);
// translate to view model
var model = new User
{
Name = user.Name,
EmailAddress = user.EmailAddress
}
// Send the view model to the view
return View(model);
}
Does it help?
source to share
You must have separate Models and ViewModels for at least two reasons:
1. Safety
The default binder in MVC binds to any relevant data fields after entering the model properties. This provides security integrity, which can be exploited if you have properties that are not intended to be updated, but are in the model (for example, fake messages with property names that are not normally displayed)
By using the ViewModel and explicitly passing every required property from the ViewModel to the actual model you are defending against this attack vector
2. Complexity
Most sensible applications will require many models and collections of models to view
eg. A basic CRM customer view can have: customer details but not ratings, a list of names and phone numbers, a summary list of recent transactions, a list of registered products, etc. They can exist in a complex set of objects with names and phone numbers in different models, the last transactions can be the order number, the total number of order lines, and only the first three SKUs, etc.
The ViewModel allows you to create only the parts and summaries needed to be displayed from the model caches and static data. The result should simplify the workflow for creating the view and make it much more testable.
Typically, the inheritance path from simple ViewModels to the final complex ViewModel is actually used
source to share